test
shenhan 2025-02-06 15:18:00 +08:00
parent a7acd273c2
commit 21e94f048c
15 changed files with 1234 additions and 237 deletions

View File

@ -59,6 +59,10 @@ We recommend using [VS Code](https://code.visualstudio.com/) with [Volar](https:
- [vitesse-nuxt-bridge](https://github.com/antfu/vitesse-nuxt-bridge) - Vitesse for Nuxt 2 with Bridge
- [vitesse-webext](https://github.com/antfu/vitesse-webext) - WebExtension Vite starter template
## rich text
- [wangEditor](https://www.wangeditor.com/v5/for-frame.html#%E5%AE%89%E8%A3%85-1) - Opinionated Astro Starter Template
## Try it now!
### Online

2
app/components.d.ts vendored
View File

@ -12,11 +12,13 @@ declare module 'vue' {
NBadge: typeof import('naive-ui')['NBadge']
NButton: typeof import('naive-ui')['NButton']
NCard: typeof import('naive-ui')['NCard']
NCascader: typeof import('naive-ui')['NCascader']
NCheckbox: typeof import('naive-ui')['NCheckbox']
NCheckboxGroup: typeof import('naive-ui')['NCheckboxGroup']
NConfigProvider: typeof import('naive-ui')['NConfigProvider']
NDatePicker: typeof import('naive-ui')['NDatePicker']
NDropdown: typeof import('naive-ui')['NDropdown']
NDynamicTags: typeof import('naive-ui')['NDynamicTags']
NForm: typeof import('naive-ui')['NForm']
NFormItem: typeof import('naive-ui')['NFormItem']
NFormItemGi: typeof import('naive-ui')['NFormItemGi']

View File

@ -49,7 +49,7 @@ async function handlePictureChange(event: Event) {
event.target.value = ''
ruleForm.value.avatar = pictureResultList[0]
}
catch (error) {
catch (error: any) {
message.error('图片上传失败')
}
}
@ -83,7 +83,9 @@ onMounted(() => {
:mask-closable="false"
>
<div class="rounded-full flex justify-center overflow-hidden mb-4">
<img class="block w-[60px] h-[60px] rounded-full" :src="ruleForm.avatar || defaultAvatar" alt="编辑">
<client-only>
<img class="block w-[60px] h-[60px] rounded-full" :src="ruleForm.avatar || defaultAvatar" alt="编辑">
</client-only>
</div>
<div class="flex justify-center mb-2">
<button class="cursor-pointer text-center text-base text-[#222] dark:text-[#fff] dark:border-[#AABEFF1A] border-0 bg-[#F1F2F8] hover:bg-[#ECEEF5] dark:bg-[#1C1D29] dark:hover:bg-[#2A2D3D] font-medium leading-[3rem] w-[116px] h-12 rounded-lg" @click="handlePictureInput">

View File

@ -3,7 +3,6 @@ import {
CircleAlert,
Download,
EllipsisVertical,
ImagePlay,
Play,
} from 'lucide-vue-next'
import { ref } from 'vue'
@ -53,7 +52,7 @@ function handleSelect(event: Event, key: string) {
//
interface TopUrlType {
[key: string]: string
[key: string | number]: string
}
const topUrl = ref<TopUrlType>({
0: 'model',
@ -75,50 +74,76 @@ async function handleTop() {
}
//
async function handleDelete() {
if (props.currentType === '0') {
interface Response {
code: number
}
async function handleDelete(): Promise<void> {
const { currentType, item } = props
let url: string
switch (currentType) {
case '0':
url = `/model/delete?id=${item.id}`
break
case '1':
url = `/WorkFlow/deleteWorkFlow?id=${item.id}`
break
default:
url = `/image/delete?id=${item.id}`
break
}
else if (props.currentType === '1') {
try {
const res = await request.get(`/WorkFlow/deleteWorkFlow?id=${props.item.id}`)
if (res.code === 200) {
//
emit('topedRefresh')
}
try {
const res: Response = await request.get(url)
if (res.code === 200) {
//
emit('topedRefresh')
}
catch (e) {}
}
else {
try {
const res = await request.get(`/image/delete/${props.item.id}`)
if (res.code === 200) {
//
emit('topedRefresh')
}
}
catch (e) {}
catch (e) {
//
console.error('删除操作失败:', e)
}
}
function getFirstImagePath(imagePaths: string): string {
if (!imagePaths)
return ''
return imagePaths.split(',')[0] || ''
}
</script>
<template>
<div>
<div v-if="currentState === 'like' && currentType === '2'">
<div
class="h-80 rounded-2xl overflow-hidden cursor-pointer relative"
class="h-80 rounded-2xl overflow-hidden cursor-pointer relative group"
@click="toDetails"
>
<img class="w-full h-full object-cover block" :src="item.userAvatar" alt="">
<div
class="absolute w-full h-full top-0 left-0 flex justify-between items-center px-4 py-4 box-border bg-[#000] bg-opacity-40"
<img
class="w-full h-full object-cover block"
:src="getFirstImagePath(item.imagePaths)"
alt=""
>
<div>
<img class="w-[40px] h-[40px] rounded-full" :src="item.avatar" alt="">
<span>元影AIATIDD</span>
<div
class="absolute w-full h-full top-0 left-0 flex justify-between px-4 py-4 box-border bg-black/40 opacity-0 group-hover:opacity-100 transition-opacity duration-300"
>
<div class="flex items-center h-6">
<img
class="w-6 h-6 rounded-full"
:src="item.userAvatar"
alt="头像"
>
<span class="ml-2 h-5 text-gray-300 text-[12px]">{{ item.userName }}</span>
</div>
<div class="flex items-center justify-center rounded-lg bg-[#fceceb] p-2">
<img src="@/assets/img/heart.png" class="w-[20px] h-[20px] mr-1" alt="">
<span class="font-bold text-[12px] text-[#ff5e5e]">123</span>
<div class="flex items-center h-7 justify-center rounded-xl bg-[#fceceb] p-2">
<img
src="@/assets/img/heart.png"
class="w-3 h-3 mr-1"
alt="❤️"
>
<span class="text-xs text-[#000]">{{ item.likeNum }}</span>
</div>
</div>
</div>
@ -128,7 +153,9 @@ async function handleDelete() {
class="h-80 rounded-2xl overflow-hidden cursor-pointer relative"
@click="toDetails"
>
<img class="w-full h-full object-cover block" :src="item.userAvatar" alt="">
<img v-if="currentType === '0'" class="w-full h-full object-cover block" :src="item.surfaceUrl" alt="">
<img v-if="currentType === '1'" class="w-full h-full object-cover block" :src="item.coverPath" alt="">
<img v-if="currentType === '2'" class="w-full h-full object-cover block" :src="item.imagePaths" alt="">
<div
v-if="currentState === 'mallProduct' && item.isTop === 1"
class="text-[#58c08e] border-[#58c08e] border-solid border-[1px] bg-white rounded-lg px-1 w-10 text-[12px] ml-2 text-center absolute top-4 right-8"
@ -150,18 +177,18 @@ async function handleDelete() {
class="modelSelectByUserIdModel w-full h-full top-0 left-0 flex px-4 py-4 box-border"
>
<div
v-if="currentState === 'mallProduct' && currentType === '0' && item.modelName"
class="text-white text-[12px] px-3 bg-[#000] bg-opacity-40 rounded-lg h-[20px]"
v-if="currentState === 'mallProduct' && currentType === '0'"
class="text-white text-[12px] px-3 bg-[#000] bg-opacity-40 rounded-lg h-[20px] leading-relaxed"
>
<span>
{{ item.modelName }}
{{ item.modelType }}
</span>
</div>
<div
v-if="currentState === 'mallProduct' && currentType === '1'"
class="text-white text-[12px] px-3 bg-[#000] bg-opacity-40 rounded-lg h-[20px]"
class="text-white text-[12px] px-3 bg-[#000] bg-opacity-40 rounded-lg h-[20px] leading-relaxed"
>
<span> 工作流 </span>
工作流
</div>
<div
v-if="currentState === 'mallProduct'"
@ -179,7 +206,7 @@ async function handleDelete() {
编辑
</div>
<div
class="menu-item text-red"
class="menu-item text-red-600"
@click="(event) => handleSelect(event, 'delete')"
>
删除
@ -196,20 +223,20 @@ async function handleDelete() {
>
<component :is="Play" class="h-[14px] w-[14px] text-white menu-icon m-1" />
<span v-if="currentType === '0'">
{{ item.reals }}
{{ item.reals || 0 }}
</span>
<span v-if="currentType === '1'">
{{ item.useNumber }}
{{ item.useNumber || 0 }}
</span>
<component
:is="Download"
class="h-[14px] w-[14px] text-white menu-icon m-1"
/>
<span v-if="currentType === '0'">
{{ item.numbers }}
{{ item.numbers || 0 }}
</span>
<span v-if="currentType === '1'">
{{ item.downloadNumber }}
{{ item.downloadNumber || 0 }}
</span>
<!-- <component
:is="ImagePlay"
@ -220,7 +247,13 @@ async function handleDelete() {
</div>
<div v-if="currentType !== '2'" class="mt-2 text-[12px] text-[#67787e]">
<div class="text-[#000] mb-1">
版本名称1 版本名称12
<span v-if="currentType === '0'">
{{ item.modelName }}
</span>
<span v-if="currentType === '1'">
{{ item.workflowName }}
</span>
<!-- <span>{{ item.userName }}</span> -->
</div>
<div class="flex">

View File

@ -0,0 +1,49 @@
<script setup>
import { onBeforeUnmount, onMounted, ref, watch } from 'vue'
import WangEditor from 'wangeditor'
const props = defineProps({
modelValue: {
type: String,
default: '',
},
})
const emit = defineEmits(['update:modelValue'])
const editorRef = ref(null)
let editor = null
onMounted(() => {
editor = new WangEditor(editorRef.value)
editor.config.placeholder = '请输入内容...'
editor.config.height = 130
editor.config.onchange = (newHtml) => {
emit('update:modelValue', newHtml)
}
editor.create()
editor.txt.html(props.modelValue)
})
watch(
() => props.modelValue,
(newValue) => {
if (editor && newValue !== editor.txt.html()) {
editor.txt.html(newValue)
}
},
)
onBeforeUnmount(() => {
if (editor) {
editor.destroy()
editor = null
}
})
</script>
<template>
<div>
<div ref="editorRef" />
</div>
</template>

View File

@ -0,0 +1,262 @@
<script setup lang="ts">
import type { FormInst } from 'naive-ui'
import { commonApi } from '@/api/common'
import { computed, watch } from 'vue'
const props = defineProps({
modelValue: {
type: Object,
required: true,
},
})
const emit = defineEmits(['update:modelValue', 'createModelsNext'])
const localForm = computed({
get() {
return props.modelValue
},
set(value) {
emit('update:modelValue', value)
},
})
const options: any[] = [
]
watch(
() => localForm.value,
(newVal) => {
emit('update:modelValue', newVal)
},
{ immediate: true, deep: true },
)
//
function handleUpdate(value: Array<string>) {
if (value.length > 3) {
return
}
localForm.value.modelProduct.tags = value.join(',')
}
const formRef = ref<FormInst | null>(null)
const rules = {
'modelProduct.modelName': {
required: true,
message: '请输入模型名称',
trigger: 'blur',
},
'modelProduct.modelType': {
required: true,
message: '请输入模型名称',
trigger: 'blur',
},
}
const modelChildCategory = ref([]) //
const model_category = ref([]) //
const categoryList = ref([])
const work_flow_functions = ref([])
async function getDictType() {
try {
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: 'work_flow_functions' }),
])
// modelPartCategory.value = res1.data
modelChildCategory.value = res2.data
model_category.value = res3.data
work_flow_functions.value = res4.data
categoryList.value = res1.data
//
categoryList.value.forEach((item: any) => {
// children
item.children = []
//
modelChildCategory.value.forEach((child) => {
// parentIddictValue
if (child.partId === item.dictCode) {
// children
item.children.push(child)
}
})
})
}
catch (error) {
console.log(error)
}
}
getDictType()
const activityList = ref([])
async function getActivityList() {
try {
const res = await request.post('/ToActivity/list', {})
activityList.value = res.rows
}
catch (error) {
console.log(error)
}
}
getActivityList()
const originalBtnList = ref([
{
label: '原创',
value: 0,
},
{
label: '转载',
value: 1,
},
])
function nextStep() {
formRef.value?.validate((errors) => {
if (!errors) {
emit('createModelsNext')
}
else {
console.log('error', errors)
}
})
}
function handleIsOriginal(value: number) {
localForm.value.modelProduct.isOriginal = value
if (value === 0) {
localForm.value.modelProduct.originalAuthorName = ''
}
}
</script>
<template>
<div>
<n-form
ref="formRef"
:label-width="80"
:model="localForm"
:rules="rules"
size="large"
>
<n-form-item label="模型名称" path="modelProduct.modelName">
<n-input v-model:value="localForm.modelProduct.modelName" placeholder="输入模型名" />
</n-form-item>
<n-form-item label="模型类型" path="modelProduct.modelType">
<n-select
v-model:value="localForm.modelProduct.modelType"
label-field="dictLabel"
value-field="dictValue"
placeholder="请选择模型类型"
:options="model_category"
/>
</n-form-item>
<div>
内容类别
</div>
<div class="-mb-5 text-gray-400 text-[12px]">
填写类别可让模型获得更精准的流量, 平台也有权基于标准修改你的类别标签
</div>
<n-form-item path="category">
<n-cascader
v-model:value="localForm.modelProduct.category"
placeholder="垂类"
:options="categoryList"
label-field="dictLabel"
value-field="dictValue"
check-strategy="child"
/>
</n-form-item>
<n-form-item path="functions" class="-mt-12">
<n-select
v-model:value="localForm.modelProduct.functions"
label-field="dictLabel"
value-field="dictValue"
placeholder="功能"
:options="work_flow_functions"
/>
</n-form-item>
<div>
标签
</div>
<div class="-mb-5 text-gray-400 text-[12px]">
添加标签将自动推荐给可能感兴趣的人
</div>
<n-form-item path="category">
<n-select
v-model:value="localForm.modelProduct.tags"
:options="options"
filterable
tag
multiple
placeholder="请选择或输入标签"
@update:value="handleUpdate"
/>
</n-form-item>
<div>
参与活动
</div>
<div class="-mb-5 text-gray-400 text-[12px]">
参与特定活动或比赛,下拉选择
</div>
<n-form-item path="activityId">
<n-select
v-model:value="localForm.modelProduct.activityId"
label-field="activityName"
value-field="id"
placeholder="请选择参与哪个活动"
:options="activityList"
/>
</n-form-item>
</n-form>
<div class="flex justify-center items-center mt-5 bg-white h-10 rounded-lg">
<div
v-for="(item, index) in originalBtnList"
:key="index"
:style="{
backgroundColor:
localForm.modelProduct.isOriginal === item.value
? 'rgba(49, 98, 255, 0.1)'
: '#fff',
color: localForm.modelProduct.isOriginal === item.value ? '#3162ff' : '#000',
}" class="flex-1 rounded-lg h-full flex items-center justify-center cursor-pointer" @click="handleIsOriginal(item.value)"
>
{{ item.label }}
</div>
</div>
<div v-if="localForm.modelProduct.isOriginal === 0" class="text-[12px]">
<div class="my-3">
魔创未来原创模型加密保护计划
</div>
<div class="text-gray-400">
原创模型加密保护计划是魔创未来推出的,为维护创作者权益保障平台健康发展,通过技术手段遏制爬取盗版侵权等不法行为,保证创作者的劳动成果得到合理回报,进而激励更多优秀原创模型的诞生
</div>
<div class="text-gray-400">
谁能加入 所有发布原创模型的作者,均可以加入本计划
</div>
<div class="my-3 text-gray-400">
加入后有何好处 1.模型加密能力 2.流量扶持 3.创作激励
</div>
<div class="text-gray-400">
详情查看 <a href="" class="text-[#3162ff] underline">魔创未来原创模型加密保护计划</a>
</div>
<div class="my-3 ">
原创声明
</div>
<div class="text-gray-400">
本人声明并承诺模型是由本人原创,相关的权利和义务由本人承担
</div>
</div>
<div v-else>
<n-form-item path="modelProduct.originalAuthorName" size="large">
<n-input v-model:value="localForm.modelProduct.originalAuthorName" placeholder="输入原创作者" />
</n-form-item>
</div>
<div class="flex justify-center items-center mt-5 text-white w-30 h-10 rounded-lg bg-[#3162ff] cursor-pointer" @click="nextStep">
下一步
</div>
</div>
</template>
<style lang="scss" scoped>
</style>

View File

@ -0,0 +1,314 @@
<script setup lang="ts">
import type { FormInst } from 'naive-ui'
import { commonApi } from '@/api/common'
import { uploadImagesInBatches } from '@/utils/uploadImg.ts'
import { Asterisk, Trash } from 'lucide-vue-next'
import { computed, onMounted, ref, watch } from 'vue'
//
const props = defineProps({
modelValue: {
type: Object,
required: true,
},
})
const emit = defineEmits(['update:modelValue', 'createModelsNext'])
const acceptTypes = '.safetensors,.ckpt,.pt,.bin,.pth,.zip,.json,.flow,.lightflow,.yaml,.yml,.onnx,.gguf,.sft'
const isDataReady = ref(false)
const modelVersionItem = {
versionName: '1.0', //
modelId: 1, //
versionDescription: '"<p>这是一个描述</p><p><img src=\"https://img1.baidu.com/it/u=3001150338,397170470&fm=253&fmt=auto&app=138&f=JPEG?w=800&h=1422\" /></p><p>这是两张图片之间的一些文字说明</p><p><img src=\"https://img12.iqilu.com/10339/clue/202405/29/68ec17f5-9621-461f-ad22-a6820a3f9cf5.jpg\" /></p>"', //
filePath: 'https://ybl2112.oss-cn-beijing.aliyuncs.com/2025/JANUARY/2/19/4/877e449c-3c0d-4630-a304-91ec110499f2.png', //
fileName: 'ddefd反问句说的', //
sampleImagePaths: 'https://ybl2112.oss-cn-beijing.aliyuncs.com/2025/JANUARY/2/19/4/877e449c-3c0d-4630-a304-91ec110499f2.png,https://ybl2112.oss-cn-beijing.aliyuncs.com/2025/JANUARY/2/19/4/877e449c-3c0d-4630-a304-91ec110499f2.png,https://ybl2112.oss-cn-beijing.aliyuncs.com/2025/JANUARY/2/19/4/877e449c-3c0d-4630-a304-91ec110499f2.png', // 20,
triggerWords: '触发词', //
isPublic: 1, // 1 2
allowFusion: 1, //
allowDownloadImage: 1, //
allowUsage: 1, // 使
isFree: 0, // 0 1
allowSoftwareUse: 1, // 使
allowCommercialUse: 1, //
//
isExclusiveModel: 1, //
}
const isPublicList = [
{
label: '公开',
value: 1,
},
{
label: '仅自己可见',
value: 2,
},
]
defineExpose({
addVersion,
})
onMounted(() => {
//
nextTick(() => {
isDataReady.value = true
})
})
const localForm = computed({
get() {
return props.modelValue
},
set(value) {
emit('update:modelValue', value)
},
})
watch(
() => localForm.value,
(newVal) => {
console.log('newVal', newVal)
emit('update:modelValue', newVal)
},
{ immediate: true, deep: true },
)
const formRef = ref<FormInst | null>(null)
const rules = {
versionName: {
required: true,
message: '请输入模型名称',
trigger: 'blur',
},
modelId: {
required: true,
message: '请输入模型名称',
trigger: 'blur',
},
}
function addVersion() {
localForm.value.modelVersionList.push(modelVersionItem)
}
const originalBtnList = ref([
{
label: '免费',
value: 0,
},
{
label: '会员下载',
value: 1,
},
])
function handleIsFree(index: number, value: number) {
localForm.value.modelVersionList[index].isFree = value
}
const model_category = ref([])
function nextStep() {
formRef.value?.validate((errors) => {
if (!errors) {
emit('createModelsNext')
}
else {
console.log('error', errors)
}
})
}
//
const uploadFileIndex = ref(0)
const fileInput = ref<HTMLInputElement | null>(null)
function triggerFileInput(index: number) {
(fileInput.value as HTMLInputElement)?.click()
uploadFileIndex.value = index
}
async function handleFileChange(event: Event) {
const target = event.target as HTMLInputElement
const files = target.files
if (files && files.length > 0) {
const res = await uploadImagesInBatches(files)
localForm.value.modelVersionList[uploadFileIndex.value].filePath = res[0].url
localForm.value.modelVersionList[uploadFileIndex.value].fileName = res[0].fileName
}
target.value = ''
}
</script>
<template>
<div v-for="(item, index) in localForm.modelVersionList" :key="index">
<n-form
ref="formRef"
:label-width="80"
:model="localForm"
:rules="rules"
size="large"
>
<n-form-item label="版本名称" path="versionName">
<n-input v-model:value="item.versionName" placeholder="请输入版本名" />
</n-form-item>
<n-form-item label="基础模型" path="modelId">
<n-select
v-model:value="item.modelId"
label-field="dictLabel"
value-field="dictValue"
placeholder="请选择基础模型"
:options="model_category"
/>
</n-form-item>
<div class="flex">
上传文件 <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">
100%
</div>
<div class="flex-1 flex items-center line-clamp">
{{
item.fileName
}}
</div>
<div>
<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>
<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 class="flex mt-6">
版本介绍 <Asterisk :size="10" color="#ff0000" class="mt-1" />
</div>
<div class="bg-white p-3 mt-2 rounded-lg">
<client-only>
<WangEditor v-model="item.versionDesc" />
<!-- <WangEditor
ref="editorRef"
v-model="content"
:height="400"
placeholder="请输入文章内容..."
:disabled="isDisabled"
:upload-img-server="/model/file"
:upload-img-headers="uploadHeaders"
@change="handleContentChange"
@focus="handleFocus"
@blur="handleBlur"
@upload-success="handleUploadSuccess"
@upload-error="handleUploadError"
/> -->
</client-only>
</div>
<!-- <div class="mt-4 space-x-4">
<n-button @click="toggleDisabled">
{{ isDisabled ? '启用编辑器' : '禁用编辑器' }}
</n-button>
<n-button @click="clearContent">
清空内容
</n-button>
<n-button @click="setContent">
设置内容
</n-button>
</div> -->
<!-- 预览区域 -->
<!-- <div class="mt-4">
<h3 class="text-lg font-bold">
预览内容
</h3>
<div
class="p-4 border rounded-lg mt-2"
v-html="content"
/>
</div> -->
<div class="mt-6">
触发词
</div>
<div class="-mb-5 text-gray-400 text-[12px]">
请输入您用来训练的单词
</div>
<n-form-item path="triggerWords">
<n-input v-model:value="item.triggerWords" placeholder="例如: 1boy" />
</n-form-item>
<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>
<div v-if="item.isPublic === 1">
<div class="mt-4 mb-1 text-gray-400 text-[12px]">
付费设置
</div>
<div class="flex justify-center items-center bg-white h-10 rounded-lg">
<div
v-for="(subItem, subIndex) in originalBtnList"
:key="subIndex"
:style="{
backgroundColor:
item.isFree === subItem.value
? 'rgba(49, 98, 255, 0.1)'
: '#fff',
color: item.isFree === subItem.value ? '#3162ff' : '#000',
}" class="flex-1 rounded-lg h-full flex items-center justify-center cursor-pointer" @click="handleIsFree(index, subItem.value)"
>
{{ subItem.label }}
</div>
</div>
<div class="mt-1 mb-2 text-gray-500 text-[12px]">
选择会员专属或会员下载视为您已经阅读 <span class="text-[#3162ff] cursor-pointer underline">会员模型许可协议</span> 并同意其中条款
</div>
<div v-if="item.isFree === 1" class="text-[12px]">
<div>会员下载模型</div>
<div class="text-gray-500">
下载模型需购买会员在线生图对所有人开放无生图次数限制会员下载的模型版本生成图片默认可商用
</div>
</div>
</div>
<div class="text-gray-400 text-[12px] mt-4">
许可范围
</div>
<div>
<div />
</div>
<div class="flex justify-center items-center mt-5 text-white w-30 h-10 rounded-lg bg-[#3162ff] cursor-pointer" @click="nextStep">
下一步
</div>
</div>
<input
ref="fileInput"
type="file"
class="hidden"
:accept="acceptTypes"
@change="handleFileChange"
>
</template>
<style lang="scss" scoped>
.line-clamp {
margin: 0 10px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-size: 12px;
color: rgb(72, 71, 71);
}
</style>

View File

@ -1,6 +1,6 @@
// middleware/auth.ts
import { authRoutes, verifyBlankRoute } from '@/constants/index'
import { useRouter } from 'vue-router'
// import { useRouter } from 'vue-router'
// const router = useRouter()
/**

View File

@ -6,8 +6,14 @@ import EditUserInfo from '@/components/EditUserInfo.vue'
import { useUserStore } from '@/stores/user'
import { formatDate } from '@/utils/index.ts'
import { debounce } from 'lodash-es'
import { onMounted, onUnmounted, ref } from 'vue'
import { nextTick, onMounted, onUnmounted, ref } from 'vue'
const loading = ref(false)
const finished = ref(false)
const total = ref(0) //
const loadingTrigger = ref(null)
const observer = ref<IntersectionObserver | null>(null)
definePageMeta({
layout: 'default',
})
@ -145,6 +151,7 @@ function initChangeParams() {
else {
initLikesParams()
}
finished.value = false //
getList()
}
// /
@ -159,6 +166,7 @@ function changeType(id: string) {
currentType.value = id
initChangeParams()
}
function initPageNUm() {
if (currentState.value === 'mallProduct') {
publishParams.value.pageNum = 1
@ -166,6 +174,7 @@ function initPageNUm() {
else {
likesParams.value.pageNum = 1
}
finished.value = false //
getList()
}
@ -242,6 +251,10 @@ interface UserData {
//
const dataList = ref([])
async function getList() {
if (loading.value || finished.value)
return
loading.value = true
let params = {}
if (currentState.value === 'mallProduct') {
params = publishParams.value
@ -249,24 +262,77 @@ async function getList() {
else {
params = likesParams.value
}
const url = urlList.value[currentState.value][currentType.value]
try {
const res = await request.post<ApiResponse<UserData>>(url, params)
if (res.code === 200) {
dataList.value = res.rows
}
else {
dataList.value = []
//
if (params.pageNum === 1) {
dataList.value = res.rows
}
else {
dataList.value = [...dataList.value, ...res.rows]
}
total.value = res.total //
//
if (dataList.value.length >= total.value) {
finished.value = true
}
//
if (currentState.value === 'mallProduct') {
publishParams.value.pageNum++
}
else {
likesParams.value.pageNum++
}
}
}
catch (err) {
dataList.value = []
finished.value = true
console.log(err)
}
finally {
loading.value = false
}
}
getList()
function topedRefresh() {
onMounted(() => {
window.addEventListener('scroll', topedRefresh)
observer.value = new IntersectionObserver(([entry]) => {
if (entry.isIntersecting && !loading.value && !finished.value) {
getList()
}
}, {
threshold: 0.1,
})
if (loadingTrigger.value) {
observer.value.observe(loadingTrigger.value)
}
})
onUnmounted(() => {
window.removeEventListener('scroll', topedRefresh)
if (observer.value) {
observer.value.disconnect()
}
})
async function topedRefresh() {
if (import.meta.client) {
await nextTick()
window.scrollTo({
top: 0,
behavior: 'smooth',
})
}
initPageNUm()
}
</script>
@ -319,7 +385,7 @@ function topedRefresh() {
<!-- User Details -->
<div class="user-info mt-4">
<div v-if="userInfo.nickName" class="nickname text-2xl font-bold">
<!-- {{ userInfo.nickName }} -->微信用户1243
{{ userInfo.nickName }}
</div>
<div v-if="userInfo.brief" class="info-desc mt-1 text-sm text-gray-700">
{{ userInfo.brief }}
@ -452,6 +518,14 @@ function topedRefresh() {
@toped-refresh="topedRefresh"
/>
</div>
<div ref="loadingTrigger" class="h-10">
<div v-if="loading" class="text-center text-gray-500">
加载中...
</div>
<div v-if="finished" class="text-center text-gray-500">
没有更多数据了
</div>
</div>
</div>
</template>

View File

@ -1,129 +1,93 @@
<template>
<n-form
ref="formRef"
:model="formData"
:rules="rules"
label-placement="left"
label-width="auto"
require-mark-placement="right-hanging"
size="large"
:style="{
maxWidth: '640px',
}"
>
<n-form-item label="模型名称" path="inputValue">
<n-input v-model:value="formData.inputValue" placeholder="Input" />
</n-form-item>
<n-form-item label="模型类型" path="inputValue">
<n-select v-model:value="formData.value" :options="cuileioptions" />
</n-form-item>
<n-form-item label="Checkbox Group" path="checkboxGroupValue">
<n-checkbox-group v-model:value="formData.checkboxGroupValue">
<n-space>
<n-checkbox value="Option 1"> Option 1 </n-checkbox>
<n-checkbox value="Option 2"> Option 2 </n-checkbox>
<n-checkbox value="Option 3"> Option 3 </n-checkbox>
</n-space>
</n-checkbox-group>
</n-form-item>
<n-form-item label="Radio Group" path="radioGroupValue">
<n-radio-group v-model:value="formData.radioGroupValue" name="radiogroup1">
<n-space>
<n-radio value="Radio 1"> Radio 1 </n-radio>
<n-radio value="Radio 2"> Radio 2 </n-radio>
<n-radio value="Radio 3"> Radio 3 </n-radio>
</n-space>
</n-radio-group>
</n-form-item>
<n-form-item label="Radio Button Group" path="radioGroupValue">
<n-radio-group v-model:value="formData.radioGroupValue" name="radiogroup2">
<n-radio-button value="Radio 1"> Radio 1 </n-radio-button>
<n-radio-button value="Radio 2"> Radio 2 </n-radio-button>
<n-radio-button value="Radio 3"> Radio 3 </n-radio-button>
</n-radio-group>
</n-form-item>
<div style="display: flex; justify-content: flex-end">
<n-button round type="primary" @click="addWorkflow"> </n-button>
</div>
</n-form>
<!-- <pre
>{{ JSON.stringify(model, null, 2) }}
</pre> -->
</template>
<script setup lang="ts">
import type { FormInst, FormItemRule } from "naive-ui";
import { useMessage } from "naive-ui";
import { defineComponent, ref } from "vue";
import { commonApi } from "@/api/common";
const formRef = ref<FormInst | null>(null);
const cuileioptions = ref([
{ label: "Option 1", value: "Option 1" },
{ label: "Option 2", value: "Option 1" },
{ label: "Option 3", value: "Option 1" },
]);
const message = useMessage();
const rules: Record<string, FormItemRule[]> = {
}
const formData = ref({
inputValue: null,
textareaValue: null,
selectValue: null,
multipleSelectValue: null,
datetimeValue: null,
nestedValue: {
path1: null,
path2: null,
},
switchValue: false,
checkboxGroupValue: null,
radioGroupValue: null,
radioButtonGroupValue: null,
inputNumberValue: null,
timePickerValue: null,
transferValue: null,
})
const addWorkflow = async() => {
try {
const params = {
modelProduct:{
modelName: '模型名称',
modelTypeId: 1, //,
category: '1', //
functions:'1', //'',
tags:'11', //string
activityId: '1', //string
import type { FormInst, FormItemRule } from 'naive-ui'
import CreateModels from '@/components/publishModel/CreateModels.vue'
import EditVersion from '@/components/publishModel/EditVersion.vue'
isOriginal:1, //??? 01
originalAuthorName:'作者名称',
},
modelVersionList:[
{
versionName:'1.0', //
modelId:1, //
versionDescription:'"<p>这是一个描述</p><p><img src=\"https://img1.baidu.com/it/u=3001150338,397170470&fm=253&fmt=auto&app=138&f=JPEG?w=800&h=1422\" /></p><p>这是两张图片之间的一些文字说明</p><p><img src=\"https://img12.iqilu.com/10339/clue/202405/29/68ec17f5-9621-461f-ad22-a6820a3f9cf5.jpg\" /></p>"', //
filePath:'https://ybl2112.oss-cn-beijing.aliyuncs.com/2025/JANUARY/2/19/4/877e449c-3c0d-4630-a304-91ec110499f2.png', //
fileName:'', //
sampleImagePaths:'https://ybl2112.oss-cn-beijing.aliyuncs.com/2025/JANUARY/2/19/4/877e449c-3c0d-4630-a304-91ec110499f2.png,https://ybl2112.oss-cn-beijing.aliyuncs.com/2025/JANUARY/2/19/4/877e449c-3c0d-4630-a304-91ec110499f2.png,https://ybl2112.oss-cn-beijing.aliyuncs.com/2025/JANUARY/2/19/4/877e449c-3c0d-4630-a304-91ec110499f2.png', //20,
triggerWords:'触发词', //
isPublic:1, // 1 2
allowFusion:1, //
allowDownloadImage:1, //
allowUsage:1, //使
allowSoftwareUse:1, //使
allowCommercialUse:1, //
//
isExclusiveModel:1,//
}
]
}
const res = await request.post("/model/insert", params);
}catch (error) {
console.log(error);
const step2Ref = ref(null)
const currentStep = ref(2)
const formData = ref({
modelProduct: {
modelName: '模型名称',
modelType: null, // ,
category: null, //
functions: null, // '',
tags: null, // string
activityId: null, // string
isOriginal: 1,
originalAuthorName: '',
},
modelVersionList: [
{
versionName: '', //
modelId: null, //
versionDescription: '"<p>这是一个描述</p><p><img src=\"https://img1.baidu.com/it/u=3001150338,397170470&fm=253&fmt=auto&app=138&f=JPEG?w=800&h=1422\" /></p><p>这是两张图片之间的一些文字说明</p><p><img src=\"https://img12.iqilu.com/10339/clue/202405/29/68ec17f5-9621-461f-ad22-a6820a3f9cf5.jpg\" /></p>"', //
filePath: 'https://ybl2112.oss-cn-beijing.aliyuncs.com/2025/JANUARY/2/19/4/877e449c-3c0d-4630-a304-91ec110499f2.png', //
fileName: '这是一个文件名文件名。。。。这是一个文件名文件这是一个文件名文件这是一个文件名文件这是一个文件名文件', //
sampleImagePaths: 'https://ybl2112.oss-cn-beijing.aliyuncs.com/2025/JANUARY/2/19/4/877e449c-3c0d-4630-a304-91ec110499f2.png,https://ybl2112.oss-cn-beijing.aliyuncs.com/2025/JANUARY/2/19/4/877e449c-3c0d-4630-a304-91ec110499f2.png,https://ybl2112.oss-cn-beijing.aliyuncs.com/2025/JANUARY/2/19/4/877e449c-3c0d-4630-a304-91ec110499f2.png', // 20,
triggerWords: '触发词', //
isPublic: 1, // 1 2
isFree: 0, // 0
allowFusion: 1, //
allowDownloadImage: 1, //
allowUsage: 1, // 使
allowSoftwareUse: 1, // 使
allowCommercialUse: 1, //
//
isExclusiveModel: 1, //
},
],
})
async function addWorkflow() {
try {
const params = {
modelProduct: {
modelName: '模型名称',
modelTypeId: 1, // ,
category: '1', //
functions: '1', // '',
tags: '11', // string
activityId: '1', // string
isOriginal: 1, // ??? 01
originalAuthorName: '作者名称',
},
modelVersionList: [
{
versionName: '1.0', //
modelId: 1, //
versionDescription: '"<p>这是一个描述</p><p><img src=\"https://img1.baidu.com/it/u=3001150338,397170470&fm=253&fmt=auto&app=138&f=JPEG?w=800&h=1422\" /></p><p>这是两张图片之间的一些文字说明</p><p><img src=\"https://img12.iqilu.com/10339/clue/202405/29/68ec17f5-9621-461f-ad22-a6820a3f9cf5.jpg\" /></p>"', //
filePath: 'https://ybl2112.oss-cn-beijing.aliyuncs.com/2025/JANUARY/2/19/4/877e449c-3c0d-4630-a304-91ec110499f2.png', //
fileName: '', //
sampleImagePaths: 'https://ybl2112.oss-cn-beijing.aliyuncs.com/2025/JANUARY/2/19/4/877e449c-3c0d-4630-a304-91ec110499f2.png,https://ybl2112.oss-cn-beijing.aliyuncs.com/2025/JANUARY/2/19/4/877e449c-3c0d-4630-a304-91ec110499f2.png,https://ybl2112.oss-cn-beijing.aliyuncs.com/2025/JANUARY/2/19/4/877e449c-3c0d-4630-a304-91ec110499f2.png', // 20,
triggerWords: '触发词', //
isPublic: 1, // 1 2
allowFusion: 1, //
isFree: 0, // 0
allowDownloadImage: 1, //
allowUsage: 1, // 使
allowSoftwareUse: 1, // 使
allowCommercialUse: 1, //
//
isExclusiveModel: 1, //
},
],
}
const res = await request.post('/model/insert', params)
}
catch (error) {
console.log(error)
}
}
function createModelsNext() {
currentStep.value = 2
}
function handleAddVersion() {
if (step2Ref.value) {
step2Ref.value?.addVersion()
}
}
// const handleValidateButtonClick = (e: MouseEvent) => {
// e.preventDefault();
@ -136,42 +100,108 @@ const addWorkflow = async() => {
// }
// });
// };
const modelPartCategory = ref([]); //
const modelChildCategory = ref([]); //
const workFlowFunctions = ref([]); //
const getDictType = async() => {
// model_part_category:[], //
// model_child_category:[], //
// work_flow_functions:[], //
try {
const [res1, res2, res3] = await Promise.all([
commonApi.dictType({ type: "model_part_category" }),
commonApi.dictType({ type: "model_child_category" }),
commonApi.dictType({ type: "work_flow_functions" }),
]);
modelPartCategory.value = res1.data;
modelChildCategory.value = res2.data;
workFlowFunctions.value = res3.data;
let categoryList = modelPartCategory;
//
categoryList.value.forEach((item) => {
// children
item.children = [];
//
modelChildCategory.value.forEach((child) => {
// parentIddictValue
if (child.partId === item.dictCode) {
// children
item.children.push(child);
}
});
});
categoryList = categoryList;
} catch (error) {
console.log(error);
}
};
</script>
<template>
<div class="mx-auto py-6">
<div class="container mx-auto w-[700px]">
<div class="step-line flex">
<div class="mr-10">
1创建模版
</div>
<div class="mr-10">
2编辑版本
</div>
<div class="mr-10">
3上传图片
</div>
<div v-if="currentStep === 2" @click="handleAddVersion">
添加版本
</div>
</div>
<div class="form-container bg-gray-100 p-4 rounded-lg">
<div v-if="currentStep === 1" class="first-step">
<CreateModels v-model="formData" @create-models-next="createModelsNext" />
</div>
<div v-if="currentStep === 2" class="second-step">
<EditVersion ref="step2Ref" v-model="formData" />
</div>
<div v-if="currentStep === 3" class="third-step">
3
</div>
</div>
</div>
<!-- <n-form
ref="formRef"
:model="formData"
:rules="rules"
label-placement="left"
label-width="auto"
require-mark-placement="right-hanging"
size="large"
:style="{
maxWidth: '640px',
}"
>
<n-form-item label="模型名称" path="inputValue">
<n-input v-model:value="formData.inputValue" placeholder="Input" />
</n-form-item>
<n-form-item label="模型类型" path="inputValue">
<n-select v-model:value="formData.value" :options="cuileioptions" />
</n-form-item>
<n-form-item label="Checkbox Group" path="checkboxGroupValue">
<n-checkbox-group v-model:value="formData.checkboxGroupValue">
<n-space>
<n-checkbox value="Option 1">
Option 1
</n-checkbox>
<n-checkbox value="Option 2">
Option 2
</n-checkbox>
<n-checkbox value="Option 3">
Option 3
</n-checkbox>
</n-space>
</n-checkbox-group>
</n-form-item>
<n-form-item label="Radio Group" path="radioGroupValue">
<n-radio-group v-model:value="formData.radioGroupValue" name="radiogroup1">
<n-space>
<n-radio value="Radio 1">
Radio 1
</n-radio>
<n-radio value="Radio 2">
Radio 2
</n-radio>
<n-radio value="Radio 3">
Radio 3
</n-radio>
</n-space>
</n-radio-group>
</n-form-item>
<n-form-item label="Radio Button Group" path="radioGroupValue">
<n-radio-group v-model:value="formData.radioGroupValue" name="radiogroup2">
<n-radio-button value="Radio 1">
Radio 1
</n-radio-button>
<n-radio-button value="Radio 2">
Radio 2
</n-radio-button>
<n-radio-button value="Radio 3">
Radio 3
</n-radio-button>
</n-radio-group>
</n-form-item>
<div style="display: flex; justify-content: flex-end">
<n-button round type="primary" @click="addWorkflow">
验证
</n-button>
</div>
</n-form> -->
</div>
<!-- <pre
>{{ JSON.stringify(model, null, 2) }}
</pre> -->
</template>

View File

@ -1,5 +1,5 @@
<script setup lang="ts">
import { commonApi } from '@/api/common'
import defaultAvatar from '@/assets/img/default-avatar.png'
import {
CircleUser,
Download,
@ -7,12 +7,13 @@ import {
HardDriveUpload,
Play,
} from 'lucide-vue-next'
import { ref } from 'vue'
import { nextTick, ref } from 'vue'
// tabs
definePageMeta({
layout: 'default',
})
const userStore = useUserStore()
const route = useRoute()
const { id } = route.params as { id: string }
const activeTab = ref(null)
@ -34,7 +35,9 @@ async function getInfo() {
versionByWorkInfo.value.forEach((item) => {
item.imagePathsList = item.imagePaths.split(',')
})
activeTab.value = versionByWorkInfo.value[0].id
nextTick(() => {
activeTab.value = versionByWorkInfo.value[0].id
})
const commentRes = await request.get(`/WorkFlowComment/comment/${res.data.id}`)
}
}
@ -73,6 +76,11 @@ async function getAttention() {
}
getAttention()
function handleSelect(event: Event, id: string) {
event.stopPropagation() //
console.log(id)
}
// async function getAttention() {
// try {
// const res = await request.get("/WorkFlowComment/comment/{modelId}");
@ -183,8 +191,8 @@ getAttention()
<div
class="flex justify-between text-[#a3a1a1] text-[12px] items-center -ml-60"
>
<div class="flex">
<div class="mr-2">
<div class="flexm justify-end">
<div v-if="detailsInfo.createTime" class="mr-2">
首发时间{{ detailsInfo.createTime }}
</div>
<div v-if="detailsInfo.updateTime">
@ -192,28 +200,64 @@ getAttention()
</div>
</div>
<div>
<img src="@/assets/img/heart.png" class="w-[14px] h-[14px] mr-2" alt="">
<component
:is="EllipsisVertical"
class="h-[18px] w-[18px] text-[#557abf] menu-icon"
/>
<div class="flex items-center relative">
<img
src="@/assets/img/heart.png"
class="w-[14px] h-[14px] cursor-pointer"
alt=""
>
<div class="group relative">
<component
:is="EllipsisVertical"
class="h-[18px] w-[48px] text-[#557abf] cursor-pointer"
/>
<div
class="absolute right-0 top-[10px] hidden group-hover:block text-[#000000] text-[12px] bg-white rounded-lg text-center px-2 py-2 w-20 mt-2 shadow-lg z-10"
>
<div class="menu-item hover:bg-gray-100 py-2 cursor-pointer rounded-lg" @click="(event) => handleSelect(event, 'report')">
举报
</div>
<div
class="menu-item hover:bg-gray-100 py-2 cursor-pointer rounded-lg"
@click="(event) => handleSelect(event, 'edit')"
>
编辑
</div>
<div class="menu-item hover:bg-gray-100 py-2 cursor-pointer rounded-lg" @click="(event) => handleSelect(event, 'delete')">
删除
</div>
</div>
</div>
</div>
</div>
<div
class="flex items-center mt-10 p-2 bg-[#f3f5f9] w-full rounded-md h-[80px] box-border"
>
<div class="w-[70px] h-[70px] rounded-full overflow-hidden mr-4">
<img
<!-- <img
src="@/assets/img/default-avatar.png"
class="w-full h-full mr-2 block"
alt=""
>
> -->
<client-only>
<NAvatar
class="w-full h-full mr-2 block"
round
size="small"
:src="
userStore.userInfo && userStore.userInfo.avatar
? userStore.userInfo.avatar
: defaultAvatar
"
/>
</client-only>
</div>
<div>
<div class="text[20px] font-bold">
微信用户ddsd
</div>
<client-only>
<div class="text[20px] font-bold">
{{ userStore.userInfo.nickName }}
</div>
</client-only>
<!-- 0代表原创 1代表转载 -->
<div v-if="detailsInfo.original === 0" class="text-[14px]">
原创作者
@ -277,7 +321,7 @@ getAttention()
</div>
</template>
<style>
<style lang="scss">
.header-num {
@apply flex items-center bg-[#f4f5f9] px-2 rounded-full;
}
@ -287,4 +331,27 @@ getAttention()
align-self: flex-start;
justify-content: space-between;
}
.n-tabs.n-tabs--line-type .n-tabs-tab.n-tabs-tab,
.n-tabs.n-tabs--bar-type .n-tabs-tab.n-tabs-tab {
color: #949494;
}
.n-tabs.n-tabs--line-type .n-tabs-tab.n-tabs-tab--active,
.n-tabs.n-tabs--bar-type .n-tabs-tab.n-tabs-tab--active {
color: #000;
font-weight: 700;
font-size: 24px;
}
.n-tabs .n-tabs-bar {
position: absolute;
bottom: 0;
height: 4px;
background: linear-gradient(90deg, #173eff 0%, #1b7dff 100%);
border-radius: 2px;
transition:
left 0.2s var(--n-bezier),
max-width 0.2s var(--n-bezier),
opacity 0.3s var(--n-bezier),
background-color 0.3s var(--n-bezier);
}
</style>

View File

@ -26,7 +26,7 @@ export async function uploadImagesInBatches(files, batchSize = 3) {
},
})
// const res = await mallProductFile(formData)
uploadResults.push(res.msg)
uploadResults.push(res.data)
}
catch (error) {
console.error(`图片上传失败: ${file.name}`, error)

View File

@ -83,7 +83,9 @@ export default defineNuxtConfig({
nitro: {
devProxy: {
'/api': {
target: 'http://1.13.246.108:8080',
// target: 'http://1.13.246.108:8080', 线上
// target: 'http://192.168.2.22:8080', // 代
target: 'http://192.168.1.69:8080', // 嗨
changeOrigin: true,
prependPath: true,
},

View File

@ -15,12 +15,14 @@
},
"dependencies": {
"@vicons/ionicons5": "^0.13.0",
"@wangeditor/editor-for-vue": "^5.1.12",
"axios": "^1.7.9",
"date-fns-tz": "^3.2.0",
"lodash-es": "^4.17.21",
"lucide-vue-next": "^0.471.0",
"naive-ui": "^2.41.0",
"pinia-plugin-persistedstate": "^4.2.0",
"wangeditor": "^4.7.15",
"zipson": "^0.2.12"
},
"devDependencies": {

View File

@ -13,6 +13,9 @@ dependencies:
'@vicons/ionicons5':
specifier: ^0.13.0
version: 0.13.0
'@wangeditor/editor-for-vue':
specifier: ^5.1.12
version: 5.1.12
axios:
specifier: ^1.7.9
version: 1.7.9
@ -31,6 +34,9 @@ dependencies:
pinia-plugin-persistedstate:
specifier: ^4.2.0
version: 4.2.0(@pinia/nuxt@0.9.0)(pinia@2.3.1)
wangeditor:
specifier: ^4.7.15
version: 4.7.15
zipson:
specifier: ^0.2.12
version: 0.2.12
@ -1316,12 +1322,19 @@ packages:
esutils: 2.0.3
dev: true
/@babel/runtime-corejs3@7.26.7:
resolution: {integrity: sha512-55gRV8vGrCIYZnaQHQrD92Lo/hYE3Sj5tmbuf0hhHR7sj2CWhEhHU89hbq+UVDXvFG1zUVXJhUkEq1eAfqXtFw==}
engines: {node: '>=6.9.0'}
dependencies:
core-js-pure: 3.40.0
regenerator-runtime: 0.14.1
dev: false
/@babel/runtime@7.26.7:
resolution: {integrity: sha512-AOPI3D+a8dXnja+iwsUqGRjr1BbZIe771sXdapOtYI531gSqpi92vXivKcq2asu/DFpdl1ceFAKZyRzK2PCVcQ==}
engines: {node: '>=6.9.0'}
dependencies:
regenerator-runtime: 0.14.1
dev: true
/@babel/standalone@7.26.7:
resolution: {integrity: sha512-Fvdo9Dd20GDUAREzYMIR2EFMKAJ+ccxstgQdb39XV/yvygHL4UPcqgTkiChPyltAe/b+zgq+vUPXeukEZ6aUeA==}
@ -2480,6 +2493,7 @@ packages:
dependencies:
is-glob: 4.0.3
micromatch: 4.0.8
napi-wasm: 1.1.3
dev: true
bundledDependencies:
- napi-wasm
@ -2818,6 +2832,20 @@ packages:
picomatch: 4.0.2
rollup: 4.34.0
/@rollup/rollup-android-arm-eabi@4.34.0:
resolution: {integrity: sha512-Eeao7ewDq79jVEsrtWIj5RNqB8p2knlm9fhR6uJ2gqP7UfbLrTrxevudVrEPDM7Wkpn/HpRC2QfazH7MXLz3vQ==}
cpu: [arm]
os: [android]
requiresBuild: true
optional: true
/@rollup/rollup-android-arm64@4.34.0:
resolution: {integrity: sha512-yVh0Kf1f0Fq4tWNf6mWcbQBCLDpDrDEl88lzPgKhrgTcDrTtlmun92ywEF9dCjmYO3EFiSuJeeo9cYRxl2FswA==}
cpu: [arm64]
os: [android]
requiresBuild: true
optional: true
/@rollup/rollup-darwin-arm64@4.34.0:
resolution: {integrity: sha512-gCs0ErAZ9s0Osejpc3qahTsqIPUDjSKIyxK/0BGKvL+Tn0n3Kwvj8BrCv7Y5sR1Ypz1K2qz9Ny0VvkVyoXBVUQ==}
cpu: [arm64]
@ -2832,6 +2860,84 @@ packages:
requiresBuild: true
optional: true
/@rollup/rollup-freebsd-arm64@4.34.0:
resolution: {integrity: sha512-kpdsUdMlVJMRMaOf/tIvxk8TQdzHhY47imwmASOuMajg/GXpw8GKNd8LNwIHE5Yd1onehNpcUB9jHY6wgw9nHQ==}
cpu: [arm64]
os: [freebsd]
requiresBuild: true
optional: true
/@rollup/rollup-freebsd-x64@4.34.0:
resolution: {integrity: sha512-D0RDyHygOBCQiqookcPevrvgEarN0CttBecG4chOeIYCNtlKHmf5oi5kAVpXV7qs0Xh/WO2RnxeicZPtT50V0g==}
cpu: [x64]
os: [freebsd]
requiresBuild: true
optional: true
/@rollup/rollup-linux-arm-gnueabihf@4.34.0:
resolution: {integrity: sha512-mCIw8j5LPDXmCOW8mfMZwT6F/Kza03EnSr4wGYEswrEfjTfVsFOxvgYfuRMxTuUF/XmRb9WSMD5GhCWDe2iNrg==}
cpu: [arm]
os: [linux]
libc: [glibc]
requiresBuild: true
optional: true
/@rollup/rollup-linux-arm-musleabihf@4.34.0:
resolution: {integrity: sha512-AwwldAu4aCJPob7zmjuDUMvvuatgs8B/QiVB0KwkUarAcPB3W+ToOT+18TQwY4z09Al7G0BvCcmLRop5zBLTag==}
cpu: [arm]
os: [linux]
libc: [musl]
requiresBuild: true
optional: true
/@rollup/rollup-linux-arm64-gnu@4.34.0:
resolution: {integrity: sha512-e7kDUGVP+xw05pV65ZKb0zulRploU3gTu6qH1qL58PrULDGxULIS0OSDQJLH7WiFnpd3ZKUU4VM3u/Z7Zw+e7Q==}
cpu: [arm64]
os: [linux]
libc: [glibc]
requiresBuild: true
optional: true
/@rollup/rollup-linux-arm64-musl@4.34.0:
resolution: {integrity: sha512-SXYJw3zpwHgaBqTXeAZ31qfW/v50wq4HhNVvKFhRr5MnptRX2Af4KebLWR1wpxGJtLgfS2hEPuALRIY3LPAAcA==}
cpu: [arm64]
os: [linux]
libc: [musl]
requiresBuild: true
optional: true
/@rollup/rollup-linux-loongarch64-gnu@4.34.0:
resolution: {integrity: sha512-e5XiCinINCI4RdyU3sFyBH4zzz7LiQRvHqDtRe9Dt8o/8hTBaYpdPimayF00eY2qy5j4PaaWK0azRgUench6WQ==}
cpu: [loong64]
os: [linux]
libc: [glibc]
requiresBuild: true
optional: true
/@rollup/rollup-linux-powerpc64le-gnu@4.34.0:
resolution: {integrity: sha512-3SWN3e0bAsm9ToprLFBSro8nJe6YN+5xmB11N4FfNf92wvLye/+Rh5JGQtKOpwLKt6e61R1RBc9g+luLJsc23A==}
cpu: [ppc64]
os: [linux]
libc: [glibc]
requiresBuild: true
optional: true
/@rollup/rollup-linux-riscv64-gnu@4.34.0:
resolution: {integrity: sha512-B1Oqt3GLh7qmhvfnc2WQla4NuHlcxAD5LyueUi5WtMc76ZWY+6qDtQYqnxARx9r+7mDGfamD+8kTJO0pKUJeJA==}
cpu: [riscv64]
os: [linux]
libc: [glibc]
requiresBuild: true
optional: true
/@rollup/rollup-linux-s390x-gnu@4.34.0:
resolution: {integrity: sha512-UfUCo0h/uj48Jq2lnhX0AOhZPSTAq3Eostas+XZ+GGk22pI+Op1Y6cxQ1JkUuKYu2iU+mXj1QjPrZm9nNWV9rg==}
cpu: [s390x]
os: [linux]
libc: [glibc]
requiresBuild: true
optional: true
/@rollup/rollup-linux-x64-gnu@4.34.0:
resolution: {integrity: sha512-chZLTUIPbgcpm+Z7ALmomXW8Zh+wE2icrG+K6nt/HenPLmtwCajhQC5flNSk1Xy5EDMt/QAOz2MhzfOfJOLSiA==}
cpu: [x64]
@ -2848,6 +2954,20 @@ packages:
requiresBuild: true
optional: true
/@rollup/rollup-win32-arm64-msvc@4.34.0:
resolution: {integrity: sha512-Vmg0NhAap2S54JojJchiu5An54qa6t/oKT7LmDaWggpIcaiL8WcWHEN6OQrfTdL6mQ2GFyH7j2T5/3YPEDOOGA==}
cpu: [arm64]
os: [win32]
requiresBuild: true
optional: true
/@rollup/rollup-win32-ia32-msvc@4.34.0:
resolution: {integrity: sha512-CV2aqhDDOsABKHKhNcs1SZFryffQf8vK2XrxP6lxC99ELZAdvsDgPklIBfd65R8R+qvOm1SmLaZ/Fdq961+m7A==}
cpu: [ia32]
os: [win32]
requiresBuild: true
optional: true
/@rollup/rollup-win32-x64-msvc@4.34.0:
resolution: {integrity: sha512-g2ASy1QwHP88y5KWvblUolJz9rN+i4ZOsYzkEwcNfaNooxNUXG+ON6F5xFo0NIItpHqxcdAyls05VXpBnludGw==}
cpu: [x64]
@ -3498,6 +3618,13 @@ packages:
- typescript
dev: true
/@wangeditor/editor-for-vue@5.1.12:
resolution: {integrity: sha512-0Ds3D8I+xnpNWezAeO7HmPRgTfUxHLMd9JKcIw+QzvSmhC5xUHbpCcLU+KLmeBKTR/zffnS5GQo6qi3GhTMJWQ==}
peerDependencies:
'@wangeditor/editor': '>=5.1.0'
vue: ^3.0.5
dev: false
/abbrev@3.0.0:
resolution: {integrity: sha512-+/kfrslGQ7TNV2ecmQwMJj/B65g5KVq1/L3SGVZ3tCYGqlzFuFCGBZJtMP99wH3NpEUyAjn0zPdPUg0D+DwrOA==}
engines: {node: ^18.17.0 || >=20.5.0}
@ -4201,6 +4328,11 @@ packages:
browserslist: 4.24.4
dev: true
/core-js-pure@3.40.0:
resolution: {integrity: sha512-AtDzVIgRrmRKQai62yuSIN5vNiQjcJakJb4fbhVw3ehxx7Lohphvw9SGNWKhLFqSxC4ilD0g/L1huAYFQU3Q6A==}
requiresBuild: true
dev: false
/core-util-is@1.0.3:
resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==}
dev: true
@ -7430,6 +7562,10 @@ packages:
resolution: {integrity: sha512-9ca1h0Xjvo9bEkE4UOxgAzLV0jHKe6LMaxo37ND2DAhhAtd0j8pR1Wxz+/goMrZO8AEZTWCmyaOsFI/W5AdpCQ==}
dev: true
/napi-wasm@1.1.3:
resolution: {integrity: sha512-h/4nMGsHjZDCYmQVNODIrYACVJ+I9KItbG+0si6W/jSjdA9JbWDoU4LLeMXVcEQGHjttI2tuXqDrbGF7qkUHHg==}
dev: true
/natural-compare@1.4.0:
resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
dev: true
@ -8770,7 +8906,6 @@ packages:
/regenerator-runtime@0.14.1:
resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==}
dev: true
/regenerator-transform@0.15.2:
resolution: {integrity: sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==}
@ -8935,10 +9070,24 @@ packages:
dependencies:
'@types/estree': 1.0.6
optionalDependencies:
'@rollup/rollup-android-arm-eabi': 4.34.0
'@rollup/rollup-android-arm64': 4.34.0
'@rollup/rollup-darwin-arm64': 4.34.0
'@rollup/rollup-darwin-x64': 4.34.0
'@rollup/rollup-freebsd-arm64': 4.34.0
'@rollup/rollup-freebsd-x64': 4.34.0
'@rollup/rollup-linux-arm-gnueabihf': 4.34.0
'@rollup/rollup-linux-arm-musleabihf': 4.34.0
'@rollup/rollup-linux-arm64-gnu': 4.34.0
'@rollup/rollup-linux-arm64-musl': 4.34.0
'@rollup/rollup-linux-loongarch64-gnu': 4.34.0
'@rollup/rollup-linux-powerpc64le-gnu': 4.34.0
'@rollup/rollup-linux-riscv64-gnu': 4.34.0
'@rollup/rollup-linux-s390x-gnu': 4.34.0
'@rollup/rollup-linux-x64-gnu': 4.34.0
'@rollup/rollup-linux-x64-musl': 4.34.0
'@rollup/rollup-win32-arm64-msvc': 4.34.0
'@rollup/rollup-win32-ia32-msvc': 4.34.0
'@rollup/rollup-win32-x64-msvc': 4.34.0
fsevents: 2.3.3
@ -9758,7 +9907,6 @@ packages:
/tslib@2.8.1:
resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
dev: true
/tsscmp@1.0.6:
resolution: {integrity: sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA==}
@ -10602,6 +10750,14 @@ packages:
vdirs: 0.1.8
vooks: 0.2.12
/wangeditor@4.7.15:
resolution: {integrity: sha512-aPTdREd8BxXVyJ5MI+LU83FQ7u1EPd341iXIorRNYSOvoimNoZ4nPg+yn3FGbB93/owEa6buLw8wdhYnMCJQLg==}
dependencies:
'@babel/runtime': 7.26.7
'@babel/runtime-corejs3': 7.26.7
tslib: 2.8.1
dev: false
/webidl-conversions@3.0.1:
resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==}
dev: true