Compare commits

...

3 Commits

Author SHA1 Message Date
shenhan 689cd88aec feature:update 2025-01-16 16:21:52 +08:00
shenhan 24c9ff4a7e first 2025-01-03 14:50:49 +08:00
shenhan 6ecfe7fa5c feat:test 2025-01-03 14:48:35 +08:00
57 changed files with 6685 additions and 117 deletions

View File

@ -27,4 +27,23 @@ npm run build:stage
# 构建生产环境
npm run build:prod
```
```
在js出发login
import Vue from "vue";
Vue.prototype.$eventBus.$emit("showLogin");
<!-- [
{},
[
{
id:'1',
name:'',
imgsur:''
},
{
id:'',
delflag:'2',
}
]
] -->

View File

@ -37,6 +37,9 @@
},
"dependencies": {
"@riophae/vue-treeselect": "0.4.0",
"@tailwindcss/postcss7-compat": "^2.2.17",
"@wangeditor/editor": "^5.1.23",
"autoprefixer": "^9.8.8",
"axios": "0.28.1",
"clipboard": "2.0.8",
"core-js": "3.37.1",
@ -48,16 +51,21 @@
"js-beautify": "1.13.0",
"js-cookie": "3.0.1",
"jsencrypt": "3.0.0-rc.1",
"lodash": "^4.17.21",
"nprogress": "0.2.0",
"quill": "2.0.2",
"postcss": "^7.0.39",
"qrcode": "^1.5.4",
"screenfull": "5.0.2",
"sortablejs": "1.10.2",
"splitpanes": "2.4.1",
"vue": "2.6.12",
"tailwindcss": "npm:@tailwindcss/postcss7-compat",
"vue": "^2.7.16",
"vue-count-to": "1.0.13",
"vue-cropper": "0.5.5",
"vue-meta": "2.4.0",
"vue-qr": "^4.0.9",
"vue-router": "3.4.9",
"vue2-editor": "^2.10.3",
"vuedraggable": "2.24.3",
"vuex": "3.6.0"
},
@ -65,6 +73,7 @@
"@vue/cli-plugin-babel": "4.4.6",
"@vue/cli-plugin-eslint": "4.4.6",
"@vue/cli-service": "4.4.6",
"autoprefixer": "latest",
"babel-eslint": "10.1.0",
"babel-plugin-dynamic-import-node": "2.3.3",
"chalk": "4.1.0",
@ -73,11 +82,14 @@
"eslint": "7.15.0",
"eslint-plugin-vue": "7.2.0",
"lint-staged": "10.5.3",
"postcss": "latest",
"runjs": "4.4.2",
"sass": "1.32.13",
"sass-loader": "10.1.1",
"script-ext-html-webpack-plugin": "2.1.5",
"svg-sprite-loader": "5.1.1",
"tailwindcss": "latest",
"ts-node": "latest",
"vue-template-compiler": "2.6.12"
},
"engines": {

View File

@ -1,16 +1,16 @@
<template>
<div id="app">
<router-view />
<theme-picker />
<McLogin ref="McLogin"></McLogin>
</div>
</template>
<script>
import ThemePicker from "@/components/ThemePicker";
import McLogin from '@/components/McLogin'
export default {
name: "App",
components: { ThemePicker },
components: { ThemePicker,McLogin },
metaInfo() {
return {
title: this.$store.state.settings.dynamicTitle && this.$store.state.settings.title,
@ -18,7 +18,16 @@ export default {
return title ? `${title} - ${process.env.VUE_APP_TITLE}` : process.env.VUE_APP_TITLE
}
}
}
},
created() {
this.$eventBus.$on("showLogin", () => {
this.$refs.McLogin.showLogin();
});
},
beforeDestroy() {
//
this.$eventBus.$off("showLogin");
},
};
</script>
<style scoped>

View File

@ -34,7 +34,7 @@ export function register(data) {
// 获取用户详细信息
export function getInfo() {
return request({
url: '/getInfo',
url: '/system/user/selectUserById',
method: 'get'
})
}

View File

@ -0,0 +1,66 @@
import request from '@/utils/request'
// 发送验证码
export function getCode(query) {
return request({
url: '/getCode',
method: 'get',
params: query
})
}
// 手机号登陆
export function phoneLogin(data) {
return request({
url: '/phoneLogin',
method: 'post',
data: data
})
}
// 登录方法
export function login(phone,code) {
const data = {
phone,
code,
}
return request({
url: '/phoneLogin',
headers: {
isToken: false,
repeatSubmit: false
},
method: 'post',
data: data
})
}
//微信扫描
// 获取uuid
export function getUUid(query) {
return request({
params:query,
url: '/wx/uuid/get',
method: 'get'
})
}
// uuid登录
export function uuidLogin(query) {
return request({
params:query,
url: '/wx/uuid/login',
method: 'get'
})
}
// 用户信息编辑
export function updateUserInfo(data) {
return request({
url: '/system/user/updateUserInfo',
method: 'post',
data: data
})
}

View File

@ -0,0 +1,63 @@
import request from '@/utils/request'
// 查询商品
export function getMallProductList(query) {
return request({
url: '/MallProduct/list',
method: 'get',
params: query
})
}
// 获取详情
export function getMallProduct(query) {
return request({
url: '/MallProduct/{id}',
method: 'get',
params: query
})
}
// 上传图片
// export function getFile(data) {
// return request({
// url: '/MallProduct/file',
// method: 'post',
// data: data
// })
// }
// 上传zip
export function getZipUrlFile(data) {
return request({
url: '/MallProduct/zipUrlFile',
method: 'post',
data: data
})
}
// 上传文件
export function uploadFile(data) {
return request({
headers: {
"Content-Type": "multipart/form-data", // 浏览器会自动添加 boundary
},
url: '/WorkFlow/file',
method: 'post',
data: data
})
}
//下载zip
export function getZipUrl(data) {
return request({
url: '/MallProduct/zipUrl',
method: 'post',
data: data
})
}
//上传图片
export function modelImagePublish(data) {
return request({
url: '/modelImage/publish',
method: 'post',
data: data
})
}

View File

@ -0,0 +1,40 @@
import request from '@/utils/request'
// 获取个人关注、粉丝、下载次数和点赞数
export function getSelectUserInfo(query) {
return request({
url: '/attention/selectUserInfo',
method: 'get',
params: query
})
}
//获取数据字典
export function dictType(query) {
return request({
url: `/system/dict/data/type/${query.type}`,
method: 'get',
// params: query
})
}
// 查看用户发布的作品
export function mallProduct(data) {
return request({
url: '/MallProduct/selectByUserId',
method: 'post',
data: data
})
}
// 查看查看点赞商品
export function selectByUserLike(data) {
return request({
url: '/like/selectByUserLike',
method: 'post',
data: data
})
}

View File

@ -0,0 +1,21 @@
import request from '@/utils/request'
// 上传图片
export function mallProductFile(data) {
return request({
headers: {
"Content-Type": "multipart/form-data", // 浏览器会自动添加 boundary
},
url: '/MallProduct/file',
method: 'post',
data: data
})
}
//实名认证
export function updateIdCard(data) {
return request({
url: '/system/user/updateIdCard',
method: 'post',
data: data
})
}

View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1735892107667" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1046" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="16"><path d="M945.93 130.759c-7.638-15.276-26.279-21.619-41.684-13.981L92.312 520.027c-15.276 7.638-21.619 26.279-13.981 41.684 1.683 3.365 3.884 6.343 6.473 8.803 3.365 3.237 7.378 5.696 12.169 7.249l273.148 85.828 41.943-52.041-222.919-70.035 611.539-303.957-327.131 395.999a22.868 22.868 0 0 0-2.071 2.848l-37.801 46.991v194.957c0 17.218 13.852 31.069 31.069 31.069s31.069-13.852 31.069-31.069v-175.54l297.097 93.206c3.495 1.036 6.991 1.553 10.485 1.423 15.017 0.388 28.609-10.227 31.457-25.502l113.79-621.507c0.388-2.071 0.517-4.272 0.517-6.343-0.13-4.402-1.036-9.062-3.237-13.333zM779.969 726.893l-240.396-75.472L866.314 255.81l-86.346 471.082z" p-id="1047"></path></svg>

After

Width:  |  Height:  |  Size: 994 B

View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1735892143936" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1686" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="16"><path d="M480 384h320a96.11 96.11 0 0 0 96-96V160a96.11 96.11 0 0 0-96-96H480a96.11 96.11 0 0 0-96 96v32H224a96.11 96.11 0 0 0-96 96v160a96.11 96.11 0 0 0 96 96h576a32 32 0 0 1 32 32v160a32 32 0 0 1-32 32H640v-32a96.11 96.11 0 0 0-96-96H224a96.11 96.11 0 0 0-96 96v128a96.11 96.11 0 0 0 96 96h320a96.11 96.11 0 0 0 96-96v-32h160a96.11 96.11 0 0 0 96-96V576a96.11 96.11 0 0 0-96-96H224a32 32 0 0 1-32-32V288a32 32 0 0 1 32-32h160v32a96.11 96.11 0 0 0 96 96z m96 480a32 32 0 0 1-32 32H224a32 32 0 0 1-32-32V736a32 32 0 0 1 32-32h320a32 32 0 0 1 32 32zM448 160a32 32 0 0 1 32-32h320a32 32 0 0 1 32 32v128a32 32 0 0 1-32 32H480a32 32 0 0 1-32-32z" p-id="1687"></path></svg>

After

Width:  |  Height:  |  Size: 991 B

View File

@ -0,0 +1 @@
<svg t="1735889157703" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="959" width="16" height="16"><path d="M512.064974 0a511.740759 511.740759 0 0 0 0 1024c83.345823 0 141.674937-19.443038 178.098228-59.625316 50.681519-55.866329 43.033924-134.156962 36.941772-197.152406-6.481013-67.143291-6.092152-96.826329 13.739747-107.455189a79.716456 79.716456 0 0 1 38.108355-9.98076c25.924051 0 53.014684 12.962025 78.549873 26.831393s48.737215 25.146329 75.179747 25.146329c90.734177 0 90.734177-118.602532 90.734177-189.50481A512.259241 512.259241 0 0 0 512.064974 0z m420.617722 650.17519c-33.701266 0-86.97519-51.848101-153.72962-51.848101a129.620253 129.620253 0 0 0-62.217722 16.072911C584.522696 684.524557 819.135354 972.151899 512.064974 972.151899A460.540759 460.540759 0 1 1 972.476114 511.740759c0 107.844051-14.128608 138.43443-39.793418 138.434431z" p-id="960"></path><path d="M526.063962 656.785823a102.4 102.4 0 1 0 102.270379 102.4 102.52962 102.52962 0 0 0-102.270379-102.4z m0 153.6a51.848101 51.848101 0 1 1 51.070379-51.848101 51.848101 51.848101 0 0 1-51.070379 51.848101z" p-id="961"></path><path d="M275.378392 572.921519a114.584304 114.584304 0 0 0-103.696203 71.80962 65.717468 65.717468 0 0 0 22.035444 76.216709c11.665823 9.203038 14.517468 22.165063 17.887594 42.515443 3.888608 22.813165 10.888101 64.810127 63.513925 64.810127 58.069873 0 71.420759-41.996962 82.17924-75.698228a225.28 225.28 0 0 1 15.55443-40.182279 87.752911 87.752911 0 0 0-1.814683-88.271392 111.343797 111.343797 0 0 0-95.659747-51.2z m52.496203 115.880506a298.126582 298.126582 0 0 0-19.183798 48.866836c-11.406582 35.77519-14.776709 40.052658-33.312405 40.052658a17.239494 17.239494 0 0 1-7.517975-1.036962 69.087595 69.087595 0 0 1-5.44405-21.516962c-3.758987-22.035443-8.684557-51.848101-36.812152-74.272405A15.035949 15.035949 0 0 1 220.678645 661.063291a63.254684 63.254684 0 0 1 55.088608-37.330633 60.791899 60.791899 0 0 1 51.848101 26.961013 36.423291 36.423291 0 0 1 0.259241 38.108354z" p-id="962"></path><path d="M379.852316 401.822785c0-52.625823-38.886076-95.400506-86.586329-95.400507a83.086582 83.086582 0 0 0-59.366076 25.924051c-10.24 10.24-23.072405 11.276962-42.904304 11.795443-21.776203 0-67.013671 1.685063-67.013671 57.551393a127.93519 127.93519 0 0 0 255.87038 0z m-204.67038 0v-5.18481a107.973671 107.973671 0 0 1 16.980253-1.166583 105.770127 105.770127 0 0 0 77.772152-26.831392c23.331646-23.331646 58.847595-5.703291 58.717975 33.182785a76.73519 76.73519 0 0 1-153.47038 0z" p-id="963"></path><path d="M471.623455 108.103291c-31.627342 0-127.93519 0-127.93519 92.678481a128.06481 128.06481 0 0 0 127.93519 127.93519c71.031899 0 156.710886-57.032911 156.710886-127.93519 0-34.608608-20.35038-92.678481-156.710886-92.678481z m0 169.413671a76.86481 76.86481 0 0 1-76.73519-76.73519c0-22.683544 5.703291-41.608101 76.73519-41.608101 31.756962 0 105.510886 4.147848 105.510886 41.608101s-60.403038 76.73519-105.510886 76.73519z" p-id="964"></path><path d="M755.232569 206.614684c-28.775696 0-46.663291 22.424304-65.458228 46.27443-5.05519 6.351392-10.499241 12.962025-16.461772 20.091139-19.961519 23.072405-36.812152 43.941266-42.774683 67.143291-7.129114 28.127595 3.240506 54.310886 30.590379 77.772152a116.658228 116.658228 0 0 0 75.438988 32.793924c28.775696 0 55.607089-14.258228 79.846076-42.385823a128.06481 128.06481 0 0 0-12.962026-180.431392 73.883544 73.883544 0 0 0-48.218734-21.257721z m22.424304 168.506329c-27.479494 31.756962-50.551899 32.405063-83.086582 4.407088-17.369114-15.16557-15.42481-22.683544-14.387848-26.701772a150.100253 150.100253 0 0 1 31.886582-46.404051c6.481013-7.517975 12.962025-14.906329 17.757975-21.776202 8.166076-10.36962 20.60962-25.924051 25.92405-26.831392 0 0 4.277468 0 14.517469 9.073417a75.568608 75.568608 0 0 1 25.92405 51.848102 76.346329 76.346329 0 0 1-18.146835 56.38481z" p-id="965"></path></svg>

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

@ -0,0 +1 @@
<svg t="1735797429104" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="992" width="16" height="16"><path d="M332.3904 813.4656h545.1776c17.8176 0 31.3344-13.312 31.3344-31.3344s-13.312-31.3344-31.3344-31.3344H332.3904c-17.8176 0-31.3344 13.312-31.3344 31.3344 0 13.312 13.5168 31.3344 31.3344 31.3344z m0-268.288h545.1776c22.3232 0 35.84-13.312 35.84-31.3344s-13.312-31.3344-31.3344-31.3344H332.3904c-17.8176-4.5056-31.3344 9.0112-31.3344 31.3344 0 18.0224 13.5168 31.3344 31.3344 31.3344z m0-263.5776h545.1776c22.3232 0 35.84-17.8176 35.84-35.84 0-17.8176-13.312-31.3344-31.3344-31.3344H332.3904c-17.8176 0-31.3344 13.312-31.3344 31.3344 0 17.8176 13.5168 35.84 31.3344 35.84zM158.1056 826.7776c26.8288 0 49.152-22.3232 49.152-49.152s-22.3232-49.152-49.152-49.152-49.152 22.3232-49.152 49.152 22.3232 49.152 49.152 49.152z m49.152-312.9344c0-26.8288-22.3232-49.152-49.152-49.152-26.8288-4.5056-49.152 17.8176-49.152 49.152 0 26.8288 22.3232 49.152 49.152 49.152s49.152-22.3232 49.152-49.152zM158.1056 294.912c26.8288 0 49.152-22.3232 49.152-49.152s-22.3232-49.152-49.152-49.152-49.152 22.3232-49.152 49.152 22.3232 49.152 49.152 49.152z m0 0" p-id="993"></path></svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1735892132852" class="icon" viewBox="0 0 1061 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1525" xmlns:xlink="http://www.w3.org/1999/xlink" width="16.578125" height="16"><path d="M447.122465 467.332105L49.240301 268.161564A33.501036 33.501036 0 0 0 0.136043 300.744763v441.020484a33.042117 33.042117 0 0 0 16.06214 27.994016L413.162511 1018.034062a33.959954 33.959954 0 0 0 17.438895 5.50702 33.042117 33.042117 0 0 0 33.042117-33.042118V497.161795a33.042117 33.042117 0 0 0-17.438895-29.82969zM398.018207 931.298504l-331.339011-208.348907v-367.134638l331.339011 162.915996zM1046.010843 263.572381a33.042117 33.042117 0 0 0-31.665363 0L550.838 467.332105a33.042117 33.042117 0 0 0-19.733487 30.288608v493.33717a33.042117 33.042117 0 0 0 49.563176 28.452934l463.048562-265.254776a33.042117 33.042117 0 0 0 16.521059-28.452934V291.566398a33.042117 33.042117 0 0 0-14.685386-27.994017z m-50.939931 441.020484L596.72983 931.298504v-413.026468l397.882163-176.224626zM991.399565 178.672496a33.042117 33.042117 0 0 0-22.486996-29.829689L550.838 1.530034a32.583199 32.583199 0 0 0-19.733487 0L83.659173 158.021173a33.042117 33.042117 0 0 0-4.130264 61.036134l397.882163 199.170541a33.042117 33.042117 0 0 0 14.685386 3.212428 33.959954 33.959954 0 0 0 13.30863 0l463.966399-205.595398a33.042117 33.042117 0 0 0 22.028078-37.172382zM494.391049 349.849021L180.490934 195.193555l358.874108-125.743613 328.126583 112.434982z m0 0" p-id="1526"></path></svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1735889652636" class="icon" viewBox="0 0 1128 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1085" xmlns:xlink="http://www.w3.org/1999/xlink" width="17.625" height="16"><path d="M1065.795918 0H62.693878C27.167347 0 0 27.167347 0 62.693878v668.734693c0 35.526531 27.167347 62.693878 62.693878 62.693878h1003.10204c35.526531 0 62.693878-27.167347 62.693878-62.693878V62.693878c0-35.526531-27.167347-62.693878-62.693878-62.693878z m0 731.428571H62.693878V62.693878h1003.10204v668.734693z" p-id="1086"></path><path d="M522.44898 773.22449v208.979592h62.693877V773.22449h-62.693877z" p-id="1087"></path><path d="M815.020408 961.306122H313.469388v62.693878h501.55102v-62.693878zM777.404082 234.057143c-6.269388-8.359184-16.718367-12.538776-25.077551-12.538776-8.359184 0-16.718367 0-25.077551 2.089796-16.718367 4.179592-35.526531 12.538776-56.42449 25.077551l-12.538776 6.269388c-27.167347-14.628571-58.514286-25.077551-94.040816-25.077551-104.489796 0-188.081633 83.591837-188.081633 188.081633 0 20.897959 4.179592 43.885714 10.44898 62.693877l-2.089796 2.089796c-14.628571 18.808163-27.167347 35.526531-35.526531 50.155102-4.179592 8.359184-6.269388 14.628571-8.359183 22.987755 0 8.359184 0 18.808163 6.269387 27.167347 12.538776 14.628571 33.436735 14.628571 48.065307 12.538776 16.718367-4.179592 35.526531-12.538776 58.514285-22.987755 31.346939 20.897959 68.963265 33.436735 110.759184 33.436734 81.502041 0 152.555102-52.244898 177.632653-125.387755l-39.706122-14.628571C681.273469 524.538776 626.938776 564.244898 564.244898 564.244898c-54.334694 0-104.489796-31.346939-127.477551-75.232653 27.167347-31.346939 64.783673-66.873469 108.669388-102.4 39.706122-33.436735 79.412245-60.604082 112.848979-81.502041 22.987755 18.808163 37.616327 41.795918 45.97551 71.053061H585.142857v41.795919h167.183674c0-27.167347-6.269388-54.334694-16.718368-77.322449 12.538776-12.538776 25.077551-27.167347 33.436735-39.706123 6.269388-10.44898 12.538776-20.897959 14.628571-31.346939 2.089796-8.359184 4.179592-22.987755-6.269387-35.52653zM388.702041 553.795918s-2.089796 0 0 0c-2.089796 0 0-2.089796 0-2.089796 4.179592-8.359184 10.44898-18.808163 18.808163-29.257142 4.179592 6.269388 10.44898 12.538776 14.628572 18.808163-14.628571 6.269388-25.077551 10.44898-33.436735 12.538775z m129.567347-200.620408c-37.616327 31.346939-71.053061 60.604082-98.220408 89.861225-2.089796-8.359184-2.089796-16.718367-2.089796-25.077551 0-81.502041 64.783673-146.285714 146.285714-146.285715 18.808163 0 35.526531 4.179592 52.244898 10.44898-29.257143 18.808163-62.693878 43.885714-98.220408 71.053061z m215.248979-75.232653c-4.179592 8.359184-12.538776 16.718367-18.808163 25.077551-6.269388-6.269388-12.538776-14.628571-18.808163-20.897959 18.808163-8.359184 33.436735-14.628571 43.885714-18.808163h2.089796c-4.179592 6.269388-6.269388 10.44898-8.359184 14.628571z" p-id="1088"></path></svg>

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1735892115074" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1207" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="16"><path d="M938.666667 553.92V768c0 64.8-52.533333 117.333333-117.333334 117.333333H202.666667c-64.8 0-117.333333-52.533333-117.333334-117.333333V256c0-64.8 52.533333-117.333333 117.333334-117.333333h618.666666c64.8 0 117.333333 52.533333 117.333334 117.333333v297.92z m-64-74.624V256a53.333333 53.333333 0 0 0-53.333334-53.333333H202.666667a53.333333 53.333333 0 0 0-53.333334 53.333333v344.48A290.090667 290.090667 0 0 1 192 597.333333a286.88 286.88 0 0 1 183.296 65.845334C427.029333 528.384 556.906667 437.333333 704 437.333333c65.706667 0 126.997333 16.778667 170.666667 41.962667z m0 82.24c-5.333333-8.32-21.130667-21.653333-43.648-32.917333C796.768 511.488 753.045333 501.333333 704 501.333333c-121.770667 0-229.130667 76.266667-270.432 188.693334-2.730667 7.445333-7.402667 20.32-13.994667 38.581333-7.68 21.301333-34.453333 28.106667-51.370666 13.056-16.437333-14.634667-28.554667-25.066667-36.138667-31.146667A222.890667 222.890667 0 0 0 192 661.333333c-14.464 0-28.725333 1.365333-42.666667 4.053334V768a53.333333 53.333333 0 0 0 53.333334 53.333333h618.666666a53.333333 53.333333 0 0 0 53.333334-53.333333V561.525333zM320 480a96 96 0 1 1 0-192 96 96 0 0 1 0 192z m0-64a32 32 0 1 0 0-64 32 32 0 0 0 0 64z" p-id="1208"></path></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1736651367860" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1267" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="16"><path d="M662.62186 561.268406c68.523788-46.884193 113.609197-126.232559 113.609197-216.401253 0-146.068057-119.020424-265.088481-265.088481-265.088481-146.072307 0-263.289697 119.020424-263.289697 263.284384 0 90.169757 45.08541 169.51706 113.61026 216.401253C206.375662 620.778086 98.177692 770.454336 98.177692 945.37731l0 0 73.936077 0 0 0c0-173.118878 131.641661-317.383901 299.353562-337.221524 1.804096 0 46.885256-3.60713 84.755343 0l3.60713 0 0 0c164.104771 23.441566 290.33733 164.101583 290.33733 335.417427l0 0 75.739111 0 0 0C924.101085 770.454336 815.903115 620.778086 662.62186 561.268406L662.62186 561.268406zM511.142576 541.431845c-110.006317 0-198.367727-88.363535-198.367727-198.36879 0-110.002067 88.362473-198.363477 198.367727-198.363477 110.001004 0 198.363477 88.36141 198.363477 198.363477C709.506053 453.069373 621.14358 541.431845 511.142576 541.431845L511.142576 541.431845zM511.142576 541.431845" fill="#272636" p-id="1268"></path></svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1736651375254" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1428" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="16"><path d="M700.667 128a96.001 96.001 0 0 1 78.505 40.746l2.733 4.104 135.997 215.994c22.525 35.776 18.916 81.878-8.384 113.667l-3.255 3.603-355.596 374.312c-20.288 21.355-54.045 22.22-75.4 1.933l-1.934-1.933-355.596-374.312c-29.119-30.651-34.641-76.563-14.122-113.098l2.483-4.172L242.095 172.85a96.001 96.001 0 0 1 76.309-44.724l4.929-0.126h377.334z m0 64H323.333a32.001 32.001 0 0 0-25.194 12.27l-1.885 2.68-135.997 215.994c-7.24 11.5-6.38 26.2 1.85 36.736l2.03 2.354L512 828.18l347.863-366.147c8.64-9.094 11.048-22.22 6.649-33.582l-1.242-2.8-1.527-2.708L727.746 206.95a32.001 32.001 0 0 0-23.807-14.783l-3.272-0.167z m-60.445 233.373l45.255 45.254L512 644.104 338.523 470.627l45.255-45.254L512 553.6l128.222-128.227z" fill="#000000" p-id="1429"></path></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 827 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 860 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 2.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

View File

@ -0,0 +1,425 @@
<template>
<div>
<el-form
class="form-content"
:model="formData"
:rules="rules"
ref="formFef"
label-width="120px"
label-position="top"
>
<el-form-item prop="modelName">
<div class="form-title">模型名称<span class="form-required">*</span></div>
<div class="input-group">
<el-input
v-model="formData.name1"
placeholder="宣传语,可填写模型系列、作者标识"
></el-input>
<span class="separator">-</span>
<el-input
v-model="formData.name2"
placeholder="模型描述,例如:精致逼人人像摄影"
></el-input>
</div>
</el-form-item>
<!-- 模型类型 -->
<el-form-item prop="type">
<div class="form-title">模型类型<span class="form-required">*</span></div>
<el-select
class="formWidth"
v-model="formData.type"
placeholder="请选择模型类型"
clearable
>
<el-option
v-for="item in model_category"
:key="item.dictValue"
:label="item.dictLabel"
:value="item.dictValue"
></el-option>
</el-select>
</el-form-item>
<!-- 内容类别 -->
<el-form-item prop="category">
<div class="form-title">内容类别</div>
<div class="form-desc">
填写类别可让模型获得更精准的流量, 平台也有权基于标准修改你的类别标签
</div>
<!-- <el-select
class="formWidth"
v-model="formData.category"
placeholder="垂类"
clearable
>
<el-option
v-for="item in categoryList"
:key="item.dictCode"
:label="item.dictLabel"
:value="item.dictCode"
></el-option>
</el-select> -->
<el-cascader
class="formWidth"
:props="{
label: 'dictLabel', // label
value: 'dictValue', // value
children: 'children', // children
}"
v-model="formData.category"
:options="categoryList"
:show-all-levels="true"
></el-cascader>
<el-select
style="margin-top: 4px"
class="formWidth"
v-model="formData.work_flow_functions"
placeholder="功能"
clearable
>
<el-option
v-for="item in work_flow_functions"
:key="item.dictValue"
:label="item.dictLabel"
:value="item.dictValue"
></el-option>
</el-select>
</el-form-item>
<!-- 标签 -->
<el-form-item prop="tags">
<div class="form-title">标签</div>
<div class="form-desc">添加标签将自动推荐给感兴趣的人</div>
<!-- <el-select
class="formWidth"
v-model="form1.tags"
multiple
filterable
allow-create
placeholder="选择或输入后按回车键添加标签"
:clearable="true"
>
<el-option
v-for="item in tags"
:key="item"
:label="item"
:value="item"
></el-option>
</el-select> -->
<el-select
class="formWidth"
v-model="formData.tags"
multiple
filterable
allow-create
default-first-option
placeholder="选择或输入后按回车键添加标签"
>
<el-option v-for="item in tags" :key="item" :label="item.label" :value="item">
</el-option>
</el-select>
</el-form-item>
<!-- 参与活动 -->
<el-form-item prop="activity">
<div class="form-title">参与活动</div>
<div class="form-desc">参加特定活动或比赛, 下拉选择</div>
<el-select
class="formWidth"
v-model="formData.activity"
placeholder="请选择参与活动"
clearable
>
<el-option
v-for="item in activities"
:key="item.dictValue"
:label="item.dictLabel"
:value="item.dictValue"
></el-option>
</el-select>
</el-form-item>
<!-- reprint -->
<!-- 原创内容 -->
<el-form-item prop="content">
<div class="form-title">原创内容<span class="form-required">*</span></div>
<div class="FormField_content">
<div class="ant-segmented-group">
<div
class="ant-segmented-group-item"
v-for="(item, index) in originalBtnList"
:key="index"
@click="changeIsOriginal(item)"
:style="{
backgroundColor:
formData.content === item.value ? 'rgba(49, 98, 255, 0.1)' : '#fff',
color: formData.content === item.value ? '#3162ff' : '#000',
}"
>
{{ item.label }}
</div>
</div>
</div>
</el-form-item>
<el-form-item prop="name" v-if="formData.content === 'reprint'">
<el-input v-model="formData.name" placeholder="请输入原创作者名"></el-input>
</el-form-item>
</el-form>
<div class="step-group">
<div class="step1-group">
<div class="step-btn step1" @click="onStepNext()"></div>
</div>
</div>
</div>
</template>
<script>
import { dictType } from "@/api/mcwl/personalCenter";
export default {
name: "CreateModels",
data() {
return {
categoryList:[],
options1: [
{
dictValue: "zhinan",
dictLabel: "指南",
children: [
{
dictValue: "yizhi",
dictLabel: "一致",
},
{
dictValue: "fankui",
dictLabel: "反馈",
},
],
},
],
model_category: [], //
model_part_category: [], //
model_child_category: [], //
chuilei: [], //
work_flow_functions: [], //
modelTypes: [
{ label: "类型1", value: "type1" },
{ label: "类型2", value: "type2" },
{ label: "类型3", value: "type3" },
],
tags: [],
activities: [],
originalBtnList: [
{ label: "原创", value: "original" },
{ label: "转载", value: "reprint" },
],
//
rules: {
modelName: [
{
validator: (rule, value, callback) => {
//
if (!this.formData.name1 && !this.formData.name2) {
callback(new Error("至少填写一个输入框内容"));
} else {
callback();
}
},
trigger: "blur", // 'change'
},
],
type: [{ required: true, message: "请输入内容", trigger: "change" }],
},
formData: {
work_flow_functions: "",
name: "",
category: "",
tags: [],
activity: "",
content: "original",
},
// categories: [],
};
},
methods: {
changeIsOriginal(item) {
this.formData.content = item.value;
},
setdata(data1, data2) {},
onStepNext() {
this.$refs.formFef.validate((valid) => {
if (valid) {
this.$emit("changeCreateModelInfo", this.formData);
this.$emit("stepNext", 2);
} else {
return false;
}
});
},
//
resetForm1() {
this.$refs.form1.resetFields();
},
async getDictType() {
// model_category:[], //
// model_part_category:[], //
// model_child_category:[], //
// chuilei:[], //
// work_flow_functions:[], //
try {
// const res = await dictType({ type: "model_category" });
// const res2 = await dictType({ type: "model_part_category" });
// const res3 = await dictType({ type: "model_child_category" });
// const res4 = await dictType({ type: "work_flow_functions" });
const [res, res2, res3, res4] = await Promise.all([
dictType({ type: "model_category" }),
dictType({ type: "model_part_category" }),
dictType({ type: "model_child_category" }),
dictType({ type: "work_flow_functions" }),
]);
this.model_category = res.data;
this.model_part_category = res2.data;
this.model_child_category = res3.data;
this.work_flow_functions = res4.data;
let categoryList = this.model_part_category;
//
categoryList.forEach((item) => {
// children
item.children = [];
//
this.model_child_category.forEach((child) => {
// parentIddictValue
if (child.partId === item.dictCode) {
// children
item.children.push(child);
}
});
});
this.categoryList = categoryList;
console.log(res2, res3);
} catch (error) {
console.log(error);
}
},
},
mounted() {
this.getDictType();
},
};
</script>
<style lang="scss" scoped>
.form-content {
.form-required{
color: red;
}
padding: 20px;
border-radius: 8px;
background-color: #f4f5f9;
font-size: 14px;
.step-group {
margin-top: 20px;
display: flex;
align-items: center;
justify-content: center;
.step-btn {
width: 200px;
height: 40px;
margin-right: 20px;
text-align: center;
line-height: 40px;
}
.step1-group {
display: flex;
background-color: blue;
border-radius: 4px;
color: #fff;
cursor: pointer;
}
}
.form-wrapper {
position: relative;
.version-form-group {
position: absolute;
right: -50px;
top: 0;
border: 1px solid #ccc;
}
}
.form2-upload-img {
.upload-img-container {
width: 100%;
height: 150px;
border: 1px dashed #ccc;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
background-color: #fff;
border-radius: 10px;
.upload-img-btn {
padding: 4px 20px;
text-align: center;
background-color: rgb(45, 40, 255);
color: #fff;
border-radius: 4px;
cursor: pointer;
}
.upload-img-tips {
font-size: 12px;
color: #999;
margin-top: 10px;
}
}
}
.nextStep {
width: 300px;
}
.input-group {
display: flex;
align-items: center;
}
.separator {
margin: 0 8px;
color: #ccc;
}
.formWidth {
width: 100%;
}
.el-form--label-top .el-form-item__label {
padding-bottom: 0 !important;
}
.el-form-item {
margin-bottom: 20px;
}
.el-button {
margin-right: 10px;
}
.FormField_content {
width: 100%;
height: 40px;
background-color: #fff;
border-radius: 4px;
.ant-segmented-group {
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
height: 100%;
.ant-segmented-group-item {
width: 50%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
border-radius: 4px;
}
}
}
}
</style>

View File

@ -0,0 +1,467 @@
<template>
<div class="container">
<div class="add-form">
<el-button type="primary" @click="addForm"></el-button>
</div>
<input
type="file"
ref="fileInput"
@change="handleFileChange"
style="display: none"
accept=".safetensors,.ckpt,.pt,.bin,.pth,.gguf,.sft"
/>
<div v-for="(form, index) in forms" :key="index" class="form-wrapper">
<div class="version-form-group">
<div class="">
<i @click="removeForm(index)" class="el-icon-delete" :size="28"></i>
</div>
<!-- <div></div>
<div></div> -->
</div>
<el-form
:model="form"
:ref="`form${index}`"
:rules="rules"
label-width="120px"
label-position="top"
>
<el-form-item prop="name1">
<div class="form-title">版本名称<span class="form-required">*</span></div>
<el-input v-model="form.name1" placeholder="请输入名称"></el-input>
</el-form-item>
<el-form-item prop="type1">
<div class="form-title">基础类型<span class="form-required">*</span></div>
<el-select v-model="form.type1" placeholder="请选择基础类型" class="formWidth">
<el-option label="类型一" value="type1"></el-option>
<el-option label="类型二" value="type2"></el-option>
<el-option label="类型三" value="type3"></el-option>
</el-select>
</el-form-item>
<el-form-item prop="type">
<div class="form2-upload-img">
<div class="form-title">上传文件<span class="form-required">*</span></div>
<div v-if="form.file"><span>100%</span>这是一个文件名</div>
<div v-else class="upload-img-container">
<div class="upload-img-btn" @click="onUploadFile(index)"></div>
<!-- <div>拖拽文件</div> -->
<div class="upload-img-tips">
支持格式.safetensors/.ckpt/.pt/.bin/.path/.gguf/.sft
</div>
</div>
</div>
</el-form-item>
<el-form-item prop="type">
<div class="form2-upload-img">
<div class="form-title">版本介绍<span class="form-required">*</span></div>
<!-- <rich-text-editor v-model="form.editorContent" /> -->
</div>
</el-form-item>
<el-form-item prop="name">
<div class="form-title">出发关键词</div>
<div class="form-desc">
填写类别可让模型获得更精准的流量, 平台也有权基于标准修改你的类别标签
</div>
<el-input v-model="form.name" placeholder="例如: 1boy"></el-input>
</el-form-item>
<el-form-item>
<div class="form-title">权限设置</div>
<div class="form-desc">可见范围</div>
<el-radio-group v-model="form.resource">
<el-radio label="公开"></el-radio>
<el-radio label="仅自己可见"></el-radio>
</el-radio-group>
</el-form-item>
<el-form-item prop="content">
<div class="form-desc">付费设置</div>
<div class="FormField_content">
<div class="ant-segmented-group">
<div
class="ant-segmented-group-item"
v-for="(item, index) in originalBtnList"
:key="index"
@click="form.content = item.value"
:style="{
backgroundColor:
form.content === item.value ? 'rgba(49, 98, 255, 0.1)' : '#fff',
color: form.content === item.value ? '#3162ff' : '#000',
}"
>
{{ item.label }}
</div>
</div>
</div>
</el-form-item>
<div style="margin-bottom: 10px">
选择会员专属或会员下载视为你已经阅读
<span style="color: blue"><<会员模型许可协议>></span> 并同意其中条款
</div>
<el-form-item>
<div class="form-desc">创作许可范围</div>
<el-checkbox-group v-model="form.type">
<el-checkbox label="允许在魔创未来在线使用" name="type"></el-checkbox>
<el-checkbox label="允许下载生图" name="type"></el-checkbox>
<el-checkbox
label="允许在魔创未来旗下其他产品在线使用"
name="type"
></el-checkbox>
<el-checkbox label="允许进行融合" name="type"></el-checkbox>
</el-checkbox-group>
</el-form-item>
<el-form-item>
<div class="form-desc">商用权限</div>
<el-checkbox-group v-model="form.type">
<el-checkbox label="生成图片可售或者用于商业目的" name="type"></el-checkbox>
<el-checkbox label="允许模型模型转售或融合后出售" name="type"></el-checkbox>
</el-checkbox-group>
</el-form-item>
<el-form-item>
<div class="form-desc">独家设置</div>
<el-checkbox-group v-model="form.type">
<el-checkbox label="" name="type">
此版本为魔创未来独家模型*获取更多流量* 独家模型规则
</el-checkbox>
</el-checkbox-group>
</el-form-item>
<!-- <el-form-item prop="description" style="margin-top: 20px;">
<div class="form-title">上传文件<span class="form-required">*</span></div>
<rich-text-editor />
</el-form-item> -->
<!-- <el-button type="danger" @click="removeForm(index)"></el-button> -->
</el-form>
</div>
<div class="step-group">
<div class="step1-group">
<div
class="step-btn step1"
style="background-color: #f1f2f7; color: #000; margin-right: 20px"
@click="onStep1Next(1)"
>
上一步
</div>
<div class="step-btn step1" @click="onStep1Next(3)"></div>
</div>
</div>
</div>
</template>
<script>
import { uploadImagesInBatches } from "@/utils/uploadImages.js";
// import RichTextEditor from "@/components/WangEditor";
import { dictType } from "@/api/mcwl/personalCenter";
import { getZipUrlFile, uploadFile } from "@/api/mcwl/mallProduct";
export default {
name: "editVersion",
data() {
return {
allowedExtensions: [
".safetensors",
".ckpt",
".pt",
".bin",
".pth",
".gguf",
".sft",
],
currentUploadIndex: 0,
rules: {
name1: [{ required: true, message: "请输入内容", trigger: "blur" }],
type1: [{ required: true, message: "请选择选项", trigger: "change" }],
},
originalBtnList: [
{
label: "原创",
value: "original",
},
{
label: "转载",
value: "reprint",
},
],
forms: [
{
name1: "",
type1: "",
type: "",
file: "",
content: "original",
description: "",
},
],
//
modelTypes: [
{ label: "类型1", value: "type1" },
{ label: "类型2", value: "type2" },
{ label: "类型3", value: "type3" },
],
//
categories: [
{ label: "垂类", value: "vertical" },
{ label: "功能", value: "function" },
],
//
tags: ["标签1", "标签2", "标签3"],
//
activities: [
{ label: "活动1", value: "activity1" },
{ label: "活动2", value: "activity2" },
{ label: "活动3", value: "activity3" },
],
};
},
components: {
// RichTextEditor,
},
methods: {
//
isFileExtensionValid(file) {
const fileName = file.name;
const fileExtension = fileName.slice(fileName.lastIndexOf(".")).toLowerCase();
return this.allowedExtensions.includes(fileExtension);
},
async handleFileChange(event) {
const files = event.target.files;
if (files.length > 1) {
alert("只能选择 1 张图片");
return;
}
let imageFiles = [];
for (let i = 0; i < files.length; i++) {
const file = files[i];
if (this.isFileExtensionValid(file)) {
imageFiles.push(file);
} else {
this.$message.error(
"文件类型不支持,请上传 .safetensors、.ckpt、.pt、.bin、。gguf、.sft 或 .pth 文件"
);
}
}
const formData = new FormData();
formData.append("file", imageFiles[0]); // 'file'
formData.append("fileName", imageFiles[0].name);
const pictureResultList = await uploadFile(formData);
},
onUploadFile(index) {
this.currentUploadIndex = index;
this.$refs.fileInput.click();
},
// form
addForm() {
this.forms.push({
name: "",
type: "",
image: "",
description: "",
});
},
//
onStep1Next(index) {
if (index == 3) {
let allValid = true;
this.forms.forEach((form, index) => {
this.$refs[`form${index}`][0].validate((valid) => {
if (!valid) {
allValid = false;
}
});
});
if (allValid) {
this.$emit("stepNext", index);
this.$emit("changeEditVersionInfo", this.forms);
//
} else {
console.log("表单验证未通过");
}
} else if (index == 1) {
this.$emit("stepNext", index);
}
},
//
removeForm(index) {
if (this.forms.length == 1) {
return;
}
this.forms.splice(index, 1);
},
async getDictType() {
try {
const res = await dictType({ type: "mall_product_status" });
const res2 = await dictType({ type: "mall_product_order" });
} catch (error) {
console.log(error);
}
},
},
};
</script>
<style lang="scss" scoped>
.container {
.add-form {
margin-top: -20px;
margin-bottom: 20px;
display: flex;
justify-content: flex-end;
}
margin: 20px;
.step-group {
display: flex;
align-items: center;
justify-content: center;
.step-btn {
width: 200px;
height: 40px;
text-align: center;
line-height: 40px;
}
.step1-group {
display: flex;
background-color: blue;
border-radius: 4px;
color: #fff;
cursor: pointer;
}
}
.steps {
display: flex;
align-items: center;
justify-content: center;
padding: 11px;
margin-bottom: 20px;
.step {
width: 60%;
}
.el-steps {
padding: 11px;
.el-step {
padding: 11px;
.el-step__head.is-finish {
padding: 11px;
.el-step__icon {
z-index: 0 !important;
}
}
}
}
}
.form-title {
line-height: 26px;
font-weight: 600;
.form-required {
margin-left: 4px;
color: #ff0000;
}
}
.FormField_content {
width: 100%;
height: 40px;
background-color: #fff;
border-radius: 4px;
.ant-segmented-group {
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
height: 100%;
.ant-segmented-group-item {
width: 50%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
border-radius: 4px;
}
}
}
.form-desc {
font-size: 12px;
line-height: 12px;
text-align: left;
color: #999;
margin: 4px 0;
}
.form-content {
.form-wrapper {
padding: 20px;
border-radius: 10px;
background-color: #f4f5f9;
font-size: 14px;
margin-bottom: 20px;
position: relative;
.version-form-group {
position: absolute;
right: -50px;
top: 0;
border: 1px solid #ccc;
}
}
.form2-upload-img {
.upload-img-container {
width: 100%;
height: 150px;
border: 1px dashed #ccc;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
background-color: #fff;
border-radius: 10px;
.upload-img-btn {
padding: 4px 20px;
text-align: center;
background-color: rgb(45, 40, 255);
color: #fff;
border-radius: 4px;
cursor: pointer;
}
.upload-img-tips {
font-size: 12px;
color: #999;
margin-top: 10px;
}
}
}
.nextStep {
width: 300px;
}
.input-group {
display: flex;
align-items: center;
}
.separator {
margin: 0 8px;
color: #ccc;
}
}
.formWidth {
width: 100%;
}
.el-form--label-top .el-form-item__label {
padding-bottom: 0 !important;
}
.el-form-item {
margin-bottom: 20px;
}
.el-button {
margin-right: 10px;
}
}
</style>

View File

@ -0,0 +1,223 @@
<template>
<div class="product-list" ref="listContainer" @scroll="handleScroll">
<div class="image-grid-container">
<!-- 商品卡片网格 -->
<div class="image-grid">
<div
class="image-card"
v-for="item in products"
:key="item.id"
>
<div class="image-wrapper">
<img src="http://img2.baidu.com/it/u=705459853,1015457524&fm=253&app=138&f=JPEG?w=800&h=1422" :alt="item.title" />
</div>
<div class="image-info">
<h3 class="title">{{ item.title }}</h3>
<p class="details">{{ item.details }}</p>
<div class="stats">
<span><i class="icon icon-view"></i>{{ item.views }}</span>
<span><i class="icon icon-like"></i>{{ item.likes }}</span>
<span><i class="icon icon-comment"></i>{{ item.comments }}</span>
</div>
</div>
</div>
</div>
</div>
<div v-if="loading" class="loading">...</div>
<div v-if="noMore" class="no-more"></div>
</div>
</template>
<script>
import { selectByUserLike} from "@/api/mcwl/personalCenter";
import _ from 'lodash';
export default {
props: {
order: {
type: String,
default: 0, // 0
}
},
watch: {
order: {
// immediate: true,
handler() {
this.resetAndFetchProducts();
},
},
},
mounted() {
this.fetchProducts();
},
data() {
return {
products: [], //
pageNumber: 1, //
pageSize: 12, //
loading: false, //
noMore: false, //
};
},
methods: {
//
throttle(func, delay) {
let lastTime = 0;
return function (...args) {
const now = new Date().getTime();
if (now - lastTime >= delay) {
lastTime = now;
func.apply(this, args);
}
};
},
//
resetAndFetchProducts() {
this.products = [];
this.pageNumber = 1;
this.noMore = false;
this.fetchProducts();
},
//
async fetchProducts() {
if (this.loading || this.noMore) return;
this.loading = true;
try {
let params = {
pageNumber: this.pageNumber,
pageSize: this.pageSize,
order: this.order, //
}
selectByUserLike(params).then((res)=>{
const newProducts = res.data.records;
if (newProducts.length < this.pageSize) {
this.noMore = true; //
}
this.products = [...this.products, ...newProducts];
this.pageNumber += 1; //
})
} catch (error) {
console.error("加载商品数据失败:", error);
} finally {
this.loading = false;
}
},
handleScroll() {
const container = this.$refs.listContainer;
if (!container) return;
const scrollTop = container.scrollTop; //
const scrollHeight = container.scrollHeight; //
const clientHeight = container.clientHeight; //
//
if (scrollTop + clientHeight >= scrollHeight - 10) {
this.fetchProducts();
}
},
},
};
</script>
<style scoped lang="scss">
.product-list {
height: 400px;
overflow-y: auto;
// border: 1px solid #ccc;
padding: 10px;
/* SCSS 样式 */
/* 变量定义 */
$background-color: #f5f5f5;
$card-bg-color: #fff;
$text-color: #333;
$sub-text-color: #555;
$icon-color: #999;
$box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
/* 容器样式 */
.image-grid-container {
// height: 100px;
padding: 20px;
background-color: $background-color;
.image-grid {
display: flex;
flex-wrap: wrap;
gap: 16px;
justify-content: flex-start;
}
.image-card {
height: 300px;
background: $card-bg-color;
border-radius: 8px;
// box-shadow: $box-shadow;
overflow: hidden;
width: calc(25% - 16px); // 4
display: flex;
flex-direction: column;
.image-wrapper {
img {
width: 100%;
height: 300px;
display: block;
}
}
.image-info {
padding: 10px;
font-size: 14px;
color: $text-color;
.title {
font-weight: bold;
font-size: 16px;
margin-bottom: 8px;
color: darken($text-color, 10%);
}
.details {
margin-bottom: 8px;
color: $sub-text-color;
}
.stats {
display: flex;
justify-content: space-between;
font-size: 12px;
color: $icon-color;
span {
display: flex;
align-items: center;
gap: 4px;
.icon {
font-size: 14px;
color: $icon-color;
}
}
}
}
}
}
}
.product-item {
margin-bottom: 15px;
padding: 10px;
// border: 1px solid #481212;
border-radius: 5px;
color: #481212;
}
.loading,
.no-more {
text-align: center;
padding: 10px;
color: #999;
}
</style>

View File

@ -0,0 +1,289 @@
<template>
<div class="container">
<div class="profile-container">
<div class="profile-header">
<div class="profile-avatar" @click="handlePictureInput">
<img :src="ruleForm.avatar" class="avatar" alt="头像" />
</div>
<input
type="file"
@change="handlePictureChange"
accept="image/*"
ref="pictureInput"
style="display: none"
/>
<!-- <el-upload
class="upload-demo"
action="#"
@change="handlePictureChange"
:on-preview="handlePreview"
:on-remove="handleRemove"
:limit="1"
:file-list="fileList">
<el-button size="small" type="primary">点击上传</el-button>
</el-upload> -->
</div>
<div class="profile-form">
<!-- <div class="form-group">
<label for="username">用户名 *</label>
<div class="input-wrapper">
<input v-model="nickName" type="text" id="username" maxlength="10" placeholder="请输入用户名" value="微信用户a98592" />
</div>
</div>
<div class="form-group">
<label for="bio">简介</label>
<textarea v-model="brief" id="bio" placeholder="请输入简介"></textarea>
</div> -->
<el-form
label-width="70px"
:model="ruleForm"
:rules="rules"
ref="ruleForm"
class="demo-ruleForm"
>
<el-form-item label="用户名" prop="nickName">
<el-input v-model="ruleForm.nickName"></el-input>
</el-form-item>
<el-form-item label="简介" prop="brief">
<el-input type="textarea" :rows="5" v-model="ruleForm.brief"></el-input>
</el-form-item>
</el-form>
<div class="form-buttons">
<button type="button" class="cancel-button" @click="closeEditInfo">
暂不修改
</button>
<button type="submit" class="submit-button" @click="onUpdate"></button>
</div>
</div>
</div>
</div>
</template>
<script>
import { updateUserInfo } from "@/api/mcwl/login";
import { uploadImagesInBatches } from "@/utils/uploadImages.js";
import { mapGetters } from "vuex";
export default {
name: "McEdit",
methods: {},
data() {
return {
fileList: [],
ruleForm: {
nickName: "",
avatar: "",
brief: "",
userId: "",
},
rules: {
nickName: [
{ required: true, message: "请输入用户名", trigger: "change" },
{ min: 3, max: 12, message: "长度在 3 到 10 个字符", trigger: "change" },
],
brief: [{ required: false, message: "请填写简介", trigger: "blur" }],
},
};
},
computed: {
...mapGetters(["nickName", "avatar", "brief", "userId"]),
},
props: {},
methods: {
handlePictureInput() {
this.$refs.pictureInput.click();
},
handleRemove(file, fileList) {
console.log(file, fileList);
},
handlePreview(file) {},
async handlePictureChange(event) {
console.log("object", event);
const files = event.target.files;
if (files.length > 1) {
alert("只能选择 1 张图片");
return;
}
let imageFiles = [];
for (let i = 0; i < files.length; i++) {
const file = files[i];
if (file.type.startsWith("image/")) {
imageFiles.push(file);
// this.imageUrls.push(URL.createObjectURL(file)); // URL
} else {
alert("请选择有效的图片文件");
}
}
const pictureResultList = await uploadImagesInBatches(imageFiles);
this.ruleForm.avatar = pictureResultList[0];
},
onUpdate() {
updateUserInfo(this.ruleForm).then((res) => {
if (res.code == 200) {
this.$message.success("修改成功");
this.closeEditInfo();
}
});
},
closeEditInfo() {
this.$emit("closeEditInfo", false);
},
},
mounted() {
this.ruleForm.nickName = this.nickName;
this.ruleForm.avatar = this.avatar;
this.ruleForm.brief = this.brief;
this.ruleForm.userId = this.userId;
console.log("ruleForm", this.userId, this.ruleForm);
},
};
</script>
<style scoped lang="scss">
body {
font-family: Arial, sans-serif;
background-color: #f7f9fc;
margin: 0;
padding: 0;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
}
.profile-container {
background: white;
border-radius: 12px;
width: 400px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
padding: 20px;
}
.profile-header {
margin-bottom: 20px;
display: flex;
justify-content: center;
align-items: center;
}
.profile-avatar {
width: 80px;
height: 80px;
border-radius: 50%;
}
.avatar {
width: 100%;
height: 100%;
border-radius: 50%;
}
.change-avatar-button {
position: absolute;
bottom: -10px;
left: 50%;
transform: translateX(-50%);
background-color: #f0f0f0;
border: none;
border-radius: 5px;
font-size: 12px;
padding: 5px 10px;
cursor: pointer;
}
.profile-form .form-group {
margin-bottom: 15px;
}
.profile-form label {
font-size: 14px;
font-weight: bold;
display: block;
margin-bottom: 5px;
}
.input-wrapper {
position: relative;
}
.input-wrapper input {
width: 100%;
padding: 10px;
border: 1px solid #d8d8d8;
border-radius: 5px;
font-size: 14px;
}
.input-wrapper .char-count {
position: absolute;
right: 10px;
top: 50%;
transform: translateY(-50%);
font-size: 12px;
color: #888;
}
textarea {
width: 100%;
height: 80px;
padding: 10px;
border: 1px solid #d8d8d8;
border-radius: 5px;
font-size: 14px;
resize: none;
}
.social-links {
display: grid;
gap: 10px;
}
.social-link {
display: flex;
align-items: center;
gap: 10px;
}
.social-link span {
white-space: nowrap;
font-size: 14px;
}
.social-link input {
flex: 1;
padding: 10px;
border: 1px solid #d8d8d8;
border-radius: 5px;
}
.form-buttons {
display: flex;
justify-content: space-between;
margin-top: 20px;
}
.cancel-button,
.submit-button {
flex: 1;
padding: 10px;
border: none;
border-radius: 5px;
cursor: pointer;
font-size: 14px;
margin: 0 5px;
}
.cancel-button {
background-color: #e0e0e0;
}
.submit-button {
background-color: #007bff;
color: white;
}
</style>

View File

@ -0,0 +1,296 @@
<template>
<div class="container">
<div class="header">
<div class="header-left">
<a
class="header-iconLogo"
style="
background-image: url('https://liblibai-web-static.liblib.cloud/liblibai_v4_online/static/_next/static/images/icon-logo.e3ce24f316fb81dbde1cafc3bf956080.svg');
"
></a>
</div>
<div class="header-right">
<!-- <div>PC客户端</div> -->
<div class="header-right-btn pc-client">
<svg-icon icon-class="mc-pckehuduan"></svg-icon>
PC客户端
</div>
<div class="header-right-btn">
<svg-icon icon-class="mc-jiaochengzhuanqu"></svg-icon>
教程专区
</div>
<div class="header-right-btn publish">
<svg-icon icon-class="mc-fabu"></svg-icon>
发布
<div class="publish-menu">
<div class="publish-menu-inner">
<div class="publish-menu-item">
<svg-icon icon-class="mc-moxing"></svg-icon>
模型
</div>
<div class="publish-menu-item" @click="onShowPublishPicture">
<svg-icon icon-class="mc-tupian"></svg-icon>
图片
</div>
<div class="publish-menu-item">
<svg-icon icon-class="mc-gongzuoliu"></svg-icon>
工作流
</div>
</div>
</div>
</div>
<div class="mc-avatar" v-if="avatar">
<img :src="avatar" alt="" class="mcwl-avatar-img" />
<div class="avatar-menu">
<div class="avatar-menu-inner">
<div class="avatar-menu-item">
<svg-icon icon-class="mc-moxing"></svg-icon>
我的模型
</div>
<div class="avatar-menu-item">
<svg-icon icon-class="mc-tupian"></svg-icon>
我的作品
</div>
<div class="avatar-menu-item">
<svg-icon icon-class="mc-gongzuoliu"></svg-icon>
我点赞的
</div>
<div class="avatar-menu-item" @click="logout">
<svg-icon icon-class="mc-gongzuoliu"></svg-icon>
退出登录
</div>
</div>
</div>
</div>
<div class="header-right-btn header-login" v-else @click="onShowLogin">
登录/注册
</div>
<!-- <div><el-button class="pc-client"><svg-icon icon-class="404" @click="click" />PC客户端</el-button></div>
<div><el-button><svg-icon icon-class="404" @click="click" />教程专区</el-button></div>
<div><el-button><svg-icon icon-class="404" @click="click" />发布</el-button></div>
<div><el-button><svg-icon icon-class="404" @click="click" />登录/注册</el-button></div> -->
</div>
</div>
<PublishWorks
@closePublishWorks="closePublishPicture"
v-if="visiblePostPicture"
></PublishWorks>
<!-- <div class="login-content">
<McLogin @onCloseLogin="onCloseLogin" @success="loginSuccess" v-if="showLogin"></McLogin>
</div> -->
</div>
</template>
<script>
import { downloadImage } from "@/utils/downloadImage";
import PublishWorks from "@/components/PublishWorks";
import { mapGetters } from "vuex";
export default {
name: "McHeader",
data() {
return {
visiblePostPicture: false,
// showLogin:false
};
},
computed: {
...mapGetters(["nickName", "avatar"]),
},
methods: {
async logout() {
this.$confirm("确定注销并退出系统吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
})
.then(() => {
this.$store.dispatch("LogOut").then(() => {
location.href = "/";
});
})
.catch(() => {});
},
onShowPublishPicture() {
this.visiblePostPicture = true;
},
closePublishPicture() {
this.visiblePostPicture = false;
},
onShowLogin() {
this.$eventBus.$emit("showLogin");
},
handleDownload() {
const imageUrl =
"https://img0.baidu.com/it/u=2191392668,814349101&fm=253&fmt=auto&app=138&f=JPEG?w=800&h=1399";
const fileName = "downloaded_image.jpg"; //
downloadImage(imageUrl, fileName);
},
},
beforeMount() {
console.log(this.nickName, "name");
// this.onGetCode()
},
mounted() {
const parent = document.querySelector(".mc-avatar");
const child = document.querySelector(".avatar-menu");
if (parent && child) {
parent.addEventListener("mouseenter", () => {
const rect = child.getBoundingClientRect();
if (rect.right > window.innerWidth) {
child.style.left = "auto"; //
child.style.right = "-10px"; //
}
});
parent.addEventListener("mouseleave", () => {
child.style.left = "50%"; //
child.style.right = "auto"; //
});
}
},
components: {
PublishWorks,
},
};
</script>
<style scoped lang="scss">
.header-btn {
color: #1890ff;
// border-color: #badeff;
}
.container {
// position: absolute;
// top: 0;
// left: 0;
// width: 100%;
// padding:0 20px;
.login-content {
position: absolute;
top: 0;
left: 0;
flex: 1;
z-index: 999;
}
.header {
padding: 10px 20px;
border-bottom: 1px solid #e5e7eb;
display: flex;
justify-content: space-between;
align-items: center;
.header-left {
.header-iconLogo {
display: block;
background-repeat: no-repeat;
width: 100px;
height: 40px;
}
}
.header-right {
display: flex;
align-items: center;
.header-right-btn {
position: relative;
padding: 6px 10px;
border-radius: 6px;
margin-right: 10px;
color: rgb(51, 51, 51);
font-weight: 500;
font-size: 14px;
background-color: rgb(241, 242, 248);
cursor: pointer;
&:hover {
color: #1890ff;
// border: 1px solid #1890ff;
// background-color: #fff;
border-color: #badeff;
}
}
.mc-avatar {
// overflow: hidden;
margin-right: 10px;
cursor: pointer;
img {
width: 40px;
height: 40px;
border-radius: 50%;
}
position: relative;
&:hover {
.avatar-menu {
display: block;
}
}
.avatar-menu {
display: none;
position: absolute;
z-index: 999;
left: -20px;
top: 40px;
background-color: #fff;
font-size: 14px;
color: rgb(51, 51, 51);
font-weight: 500;
.avatar-menu-inner {
border-radius: 10px;
margin-top: 10px;
width: 120px;
padding: 10px 20px;
border: 1px solid #e5e7eb;
.avatar-menu-item {
&:hover {
color: #1890ff;
}
color: #2d2d2e;
padding: 8px 0;
> svg {
margin-right: 4px;
}
}
}
}
}
.publish {
position: relative;
&:hover {
.publish-menu,
publish-menu:hover {
display: block;
}
}
.publish-menu {
display: none;
position: absolute;
z-index: 999;
left: -20px;
top: 30px;
background-color: #fff;
.publish-menu-inner {
border-radius: 10px;
margin-top: 10px;
width: 110px;
padding: 10px 20px;
border: 1px solid #e5e7eb;
.publish-menu-item {
&:hover {
color: #1890ff;
}
color: #2d2d2e;
padding: 8px 0;
> svg {
margin-right: 4px;
}
}
}
}
}
.pc-client {
color: #1890ff;
border: 1px solid #1890ff;
background-color: #fff;
border-color: #badeff;
}
}
}
}
</style>

View File

@ -0,0 +1,333 @@
<template>
<div v-if="isVisible" class="login-container">
<div class="login-box">
<i class="el-icon-close close-login" @click="onCloseLogin(false)"></i>
<div class="login-form">
<h2 class="title">{{ loginModeDescriptions[currentLoginMode].title }}</h2>
<p class="subtitle">{{ loginModeDescriptions[currentLoginMode].des }}</p>
<el-form
v-if="currentLoginMode === 'phone'"
ref="ruleFormRef"
:model="ruleForm"
:rules="rules"
label-width="0"
>
<el-form-item prop="phone">
<el-input
v-model="ruleForm.phone"
placeholder="请输入手机号"
>
<!-- <template #prepend>
+86
</template> -->
</el-input>
</el-form-item>
<el-form-item prop="code">
<el-input v-model="ruleForm.code" placeholder="请输入验证码">
<template #suffix>
<el-button
type="primary"
size="small"
class="code-button"
:disabled="codeButtonDisabled"
@click="onGetCode"
>
{{ codeButtonText }}
</el-button>
</template>
</el-input>
</el-form-item>
<el-form-item>
<!-- <el-checkbox v-model="form.agree">
点击登录代表同意
<a href="#/user-agreement">用户协议</a>
<a href="#/privacy-policy">隐私政策</a>
</el-checkbox> -->
<div class="agreement-text">
<div>点击登录代表同意</div>
<div class="agreement-link">用户协议隐私政策</div>
</div>
</el-form-item>
<div class="login-button" @click="submitForm(ruleFormRef)"></div>
</el-form>
<div v-if="currentLoginMode === 'wechat'" class="wechat-qs">
<div class="qr-code">
<McWechatLoginQr />
</div>
</div>
</div>
<div class="other-login-methods">
<div>
<span>其他登录方式</span>
</div>
<div class="icons-container">
<div class="icon-item" @click="setCurrentLoginMode(currentLoginMode)">
<img :src="loginModeDescriptions[currentLoginMode].src" alt="" />
</div>
<!-- <div class="icon-item">
<img src="../../assets/images/icon/icon-qq.png" alt="" />
</div> -->
</div>
</div>
</div>
</div>
</template>
<script>
import { getCode } from "@/api/mcwl/login";
import McWechatLoginQr from "@/components/McWechatLoginQr";
export default {
name: "McLogin",
data(){
return{
isVisible: false, //
rules:{
phone: [
{ required: true, message: '请输入手机号', trigger: 'change' },
{ pattern: /^1[3-9]\d{9}$/, message: '手机号格式不正确', trigger: 'blur' }
],
code: [
{ required: true, message: '请输入验证码', trigger: 'change' },
{ len: 4, message: '验证码长度为4位', trigger: 'blur' }
]
},
codeButtonText:'获取验证码',
codeButtonDisabled:false,
timerCode:null,
ruleForm:{
phone: '15888888888',
code: ''
},
ruleFormRef:null,
currentLoginMode:'phone',
loginModeDescriptions:{
phone: {
title: '登录',
des: '如未注册,验证后自动登录',
src: require('@/assets/images/phone.png')
},
wechat: {
title: '微信一键登录',
des: '关注后自动登录',
src: require('@/assets/images/wechat.png')
}
}
}
},
components:{
McWechatLoginQr
},
methods: {
closeLogin() {
this.isVisible = false;
},
showLogin() {
if (this.isVisible) return;
this.isVisible = true; //
},
onCloseLogin(ag){
this.isVisible =false
this.$emit('onCloseLogin', ag)
},
toggleMode(mode){
return mode === 'phone' ? 'wechat' : mode === 'wechat' ? 'phone' : mode
},
setCurrentLoginMode(mode){
this.currentLoginMode = this.toggleMode(mode)
},
async submitForm (){
// const res = await phoneLogin({...this.ruleForm})
this.$refs.ruleFormRef.validate(valid => {
if (valid) {
// this.loading = true;
// if (this.loginForm.rememberMe) {
// Cookies.set("username", this.loginForm.username, { expires: 30 });
// Cookies.set("password", encrypt(this.loginForm.password), { expires: 30 });
// Cookies.set('rememberMe', this.loginForm.rememberMe, { expires: 30 });
// } else {
// Cookies.remove("username");
// Cookies.remove("password");
// Cookies.remove('rememberMe');
// }
this.$store.dispatch("Login", this.ruleForm).then(() => {
this.onCloseLogin()
// this.$router.push({ path: this.redirect || "/" }).catch(()=>{});
location.href = "/";
}).catch(() => {
});
}
});
},
async onGetCode () {
if (!this.ruleForm.phone || !/^1[3-9]\d{9}$/.test(this.ruleForm.phone)) {
// ElMessage.error('')
return
}
try{
const res = await getCode({phone:this.ruleForm.phone})
console.log(res);
this.codeButtonDisabled = true
let countdown = 60
this.codeButtonText = `${countdown}秒后重试`
this.timerCode = window.setInterval(() => {
countdown--
if (countdown <= 0) {
clearInterval(this.timerCode)
this.codeButtonDisabled = false
this.codeButtonText = '获取验证码'
} else {
this.codeButtonText = `${countdown}秒后重试`
}
}, 1000)
// ElMessage.success('')
}catch(err){
console.log(err);
}
}
},
};
</script>
<style scoped lang="scss">
.el-input--medium .el-input__inner{
height: 42px !important;
line-height: 42px !important;
}
.login-container {
position: fixed;
top: 0;
left: 0;
z-index: 9999;
width: 100vw;
height: 100vh;
background-color: rgba($color: #000000, $alpha: 0.7);
display: flex;
justify-content: center;
align-items: center;
height: calc(100vh - $titleBarHeight);
.login-box {
position: relative;
width: 360px;
padding: 40px;
background: #fff;
border-radius: 10px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
.close-login{
position: absolute;
cursor: pointer;
right: -30px;
color: #fff;
font-size: 24px;
top: 0;
&:hover{
transform: scale(1.2);
}
}
.wechat-qs {
text-align: center;
}
.agreement-text {
font-size: 12px;
color: #999;
display: flex;
.agreement-link {
color: #409eff;
cursor: pointer;
}
}
.login-button {
background-color: rgb(45, 85, 255);
text-align: center;
border-radius: 10px;
cursor: pointer;
color: #fff;
font-size: 20px;
width: 100%;
line-height: 50px;
}
.code-button {
background-color: rgba($color: #fff, $alpha: 0);
border: none;
color: #409eff;
}
.title {
font-size: 24px;
font-weight: bold;
text-align: center;
margin-bottom: 10px;
color: #333;
}
.subtitle {
text-align: center;
color: #666;
margin-bottom: 14px;
font-size: 14px;
}
//
.el-form-item {
margin-bottom: 20px;
.el-input,
.el-select {
height: 40px; //
line-height: 40px;
box-sizing: border-box; //
}
//
.region-select {
.el-input {
height: 40px;
line-height: 40px;
}
}
.el-button {
height: 40px;
line-height: 40px;
padding: 0 15px;
}
}
.el-checkbox {
font-size: 14px;
color: #666;
a {
color: #409eff;
text-decoration: none;
&:hover {
text-decoration: underline;
}
}
}
.other-login-methods {
margin-top: 20px;
text-align: center;
font-size: 14px;
color: #999;
.icons-container {
margin-top: 20px;
display: flex;
justify-content: center;
align-items: center;
.icon-item {
height: 48px;
padding: 0px 20px;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
}
}
}
}
}
</style>

View File

@ -0,0 +1,301 @@
<template>
<div class="container">
<div class="mcwl-siderbar" v-for="(item,index) in sideBarList">
<div class="mcwl-siderbar-title">
探索
</div>
<!-- <div class="siderbar-item" :style="{border:item.dashed ? '1px dashed rgb(208 208 208)' : ''}" v-for="(subItem,subIndex) in item.list" :key="subIndex" @click="handleRoute(subItem)">
<div class="siderbar-icon">
<svg-icon icon-class="pdf"></svg-icon>
</div>
<div class="siderbar-menu">
<div class="siderbar-menu-text">
{{ subItem.text }}
</div>
<div class="siderbar-menu-des">
{{ subItem.desc }}
</div>
</div>
</div> -->
<div class="siderbar-item" @click="handleRoute()">
<div class="siderbar-icon">
<svg-icon icon-class="userCenter"></svg-icon>
</div>
<div class="siderbar-menu">
<div class="siderbar-menu-text">
模型广场
</div>
</div>
</div>
</div>
<div class="mcwl-siderbar" v-for="(item,index) in sideBarList" :key="index">
<div class="mcwl-siderbar-title">
{{ item.title }}
</div>
<!-- <div class="siderbar-item" :style="{border:item.dashed ? '1px dashed rgb(208 208 208)' : ''}" v-for="(subItem,subIndex) in item.list" :key="subIndex" @click="handleRoute(subItem)">
<div class="siderbar-icon">
<svg-icon icon-class="pdf"></svg-icon>
</div>
<div class="siderbar-menu">
<div class="siderbar-menu-text">
{{ subItem.text }}
</div>
<div class="siderbar-menu-des">
{{ subItem.desc }}
</div>
</div>
</div> -->
<div class="siderbar-item" @click="handleRoute()">
<div class="siderbar-icon">
<svg-icon icon-class="userCenter"></svg-icon>
</div>
<div class="siderbar-menu">
<div class="siderbar-menu-text">
个人中心
</div>
</div>
</div>
<div class="siderbar-item" @click="handleRoute()">
<div class="siderbar-icon">
<svg-icon icon-class="vipCenter"></svg-icon>
</div>
<div class="siderbar-menu">
<div class="siderbar-menu-text">
会员中心
</div>
</div>
</div>
</div>
<div class="footer-content">
<div class="join-us">
<svg-icon icon-class="pdf"></svg-icon>
加入我们
</div>
<div class="platform-content">
<div class="platform-item">
微信公众号
</div>
<div class="platform-item">
小红书
</div>
<div class="platform-item">
抖音
</div>
<div class="platform-item">
B站
</div>
</div>
<div class="platform-content">
<div>
用户协议
</div>
<div>
隐私政策
</div>
<div>
关于我们
</div>
</div>
<div class="footer-text">
<div>
上海辰风互娱网络科技有限公司
</div>
<div>
京IPC备234324324号
</div>
<div>
网信算备
</div>
<div>
23423432432432423
</div>
<div>
生成式人工智能服务管理暂行办法
</div>
<div>
备案号shanghai-sefef-23434
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: "McSideBar",
data(){
return{
sideBarList:[
// {
// id:1,
// title:'',
// dashed:false,
// list:[
// {
// id:11,
// icon:'',
// text:'广',
// desc:''
// },
// {
// id:12,
// icon:'',
// text:'',
// desc:''
// },
// {
// id:13,
// icon:'',
// text:'',
// desc:''
// },
// ]
// },
// {
// id:2,
// title:'',
// dashed:true,
// list:[
// {
// id:21,
// icon:'',
// text:'线',
// desc:'Web UI'
// },
// {
// id:22,
// icon:'',
// text:'线',
// desc:'Comfy UI'
// },
// {
// id:23,
// icon:'',
// text:'LoRA'
// },
// {
// id:24,
// icon:'',
// text:''
// },
// ]
// },
{
id:3,
title:'其他',
dashed:false,
list:[
// {
// id:31,
// icon:'',
// text:'API',
// },
// {
// id:32,
// icon:'',
// text:'',
// },
{
path: 'personalCenter',
id:33,
icon:'',
text:'个人中心',
},
{
id:34,
icon:'',
text:'会员中心',
}
]
}
]
}
},
methods: {
handleRoute(){
this.$emit('handleRoute','/publishModel')
}
},
};
</script>
<style scoped lang="scss">
.container{
overflow: auto; /* 内容可滚动 */
scrollbar-width: none; /* 仅适用于 Firefox隐藏滚动条 */
-ms-overflow-style: none; /* 仅适用于 IE 和 Edge */
color: #4e4e4e;
width: 220px;
height: calc(100vh - 61px);
border-right:1px solid #e7e7e7;
.mcwl-siderbar{
font-size: 14px;
padding:10px 20px;
.mcwl-siderbar-title{
color: rgb(156, 163, 175);
font-size: 12px;
}
.siderbar-item-dashed{
border: 1px dashed #818080;
}
.siderbar-item{
border-radius: 10px;
padding: 10px 8px;
margin-top: 8px;
cursor: pointer;
display: flex;
.siderbar-icon{
line-height: 20px;
margin-right: 4px;
> svg{
font-size: 14px;
margin-right: 8px;
}
}
.siderbar-menu{
display: flex;
flex-direction: column;
justify-content: center;
.siderbar-menu-des{
margin-top: 4px;
color: #8e8e8e;
font-size: 12px;
}
}
}
}
.footer-content{
padding: 20px;
.join-us{
width: auto;
line-height: 30px;
font-size: 14px;
text-align: center;
border: 1px dashed #818080;
border-radius: 6px;
margin-bottom: 10px;
}
.platform-content{
display: flex;
flex-wrap: wrap;
font-size: 12px;
.platform-item{
padding: 4px 6px;
}
}
.footer-text{
font-size:12px;
color:#8e8e8e;
>div{
margin-top: 6px;
}
}
}
}
</style>

View File

@ -0,0 +1,130 @@
<template>
<div class="container">
<div class="wechat-login-container">
<div v-if="bindTimeout" class="tipTimeout" @click="onGetUUid">
刷新二维码
<el-icon :size="30"><Refresh /></el-icon>
<!-- <i class="el-icon-refresh" @click="onGetUUid"></i> -->
</div>
<div class="qrcode-wrapper" v-if="qrUrl">
<!-- <canvas ref="qrcodeCanvas"></canvas> -->
<VueQr id="vueQr" :text="qrUrl" :size="200" style="margin: 0 auto;display: block;"></VueQr>
<!-- <qrcode-vue :value="qrUrl" :size="200" level="M" /> -->
<!-- <qrcode-vue :value="qrUrl" :size="200" level="M" /> -->
<!-- <div class="refresh-tip" v-if="needRefresh">
二维码已过期点击刷新
<button @click="generateQrCode"></button>
</div> -->
</div>
<div v-else class="loading">
加载中...
</div>
</div>
</div>
</template>
<script>
import VueQr from 'vue-qr'
import { getUUid, uuidLogin } from "@/api/mcwl/login";
export default {
name: "McWechatLoginQr",
data(){
return{
qrUrl:'',
bindTimeout:null,
pollingTimer:null,
}
},
components: {
VueQr
},
methods: {
async onGetUUid(){
try {
const res = await getUUid({})
if (res.code === 200) {
const localIP = 'http://p7sjuc.natappfree.cc'
const appid = 'wx82d4c3c96f0ffa5b'
if (localIP) {
const { uuid } = res
const redirect_uri = `http://p7sjuc.natappfree.cc/wx/uuid/bind/openid?uuid=${uuid}`
const codeUrl = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appid}&redirect_uri=${encodeURIComponent(redirect_uri)}&response_type=code&scope=snsapi_userinfo&state=123456#wechat_redirect`
this.qrUrl = codeUrl
let counter = 1
this.pollingTimer && clearTimeout(this.pollingTimer)
this.pollingTimer = setInterval(function () {
uuidLogin({
uuid: uuid
})
.then((res) => {
counter++
if (counter === 59) {
clearTimeout(this.pollingTimer)
this.bindTimeout = true
}
if (res.status === 1) {
clearTimeout(this.pollingTimer)
// store.userInfo = res.data
// router.push('./home')
// store.dispatch("uuidLogin", res)
// that.$store.dispatch("uuidLogin", res)
// setTimeout(() => {
// that.$router.push({
// path: that.redirect || "/"
// }).catch(() => {});
// }, 1500)
}
})
.catch((err) => {
console.log(err)
clearTimeout(this.pollingTimer)
})
}, 1000)
}
}
} catch (error) {
console.log(error)
}
}
},
mounted() {
this.onGetUUid()
},
};
</script>
<style scoped lang="scss">
.wechat-login-container {
width: 280px;
padding:0 20px;
text-align: center;
position: relative;
.tipTimeout{
position: absolute;
top: 0;
left: 0;
z-index: 9999;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
width: 100%;
cursor: pointer;
height: 100%;
color: #fff;
background-color: rgba($color: #000000, $alpha: 0.5);
.qrcode-wrapper {
position: relative;
}
.loading {
padding: 20px;
color: #999;
}
// opacity:0.3
}
}
</style>

View File

@ -0,0 +1,212 @@
<template>
<div class="container ">
<div class="profile-container">
<div class="tip">一天只能认证三次</div>
<div class="profile-form">
<el-form label-width="84px" :model="ruleForm" :rules="rules" ref="formRef" class="demo-ruleForm">
<el-form-item label="姓名" prop="name">
<el-input v-model="ruleForm.name"></el-input>
</el-form-item>
<el-form-item label="身份证号" prop="idCard">
<el-input v-model="ruleForm.idCard"></el-input>
</el-form-item>
</el-form>
<div class="form-buttons">
<button type="button" class="cancel-button" @click="closeEditInfo"></button>
<button type="submit" class="submit-button" @click="onUpdate"></button>
</div>
</div>
</div>
</div>
</template>
<script>
import { mapGetters } from 'vuex';
import {updateIdCard} from '@/api/mcwl/utils'
export default {
name: "McNameAuth",
computed: {
...mapGetters(['userId']),
},
data() {
const idCardPattern = /^[1-9]\d{5}(18|19|20)\d{2}(0[1-9]|1[0-2])(0[1-9]|[1-2]\d|3[0-1])\d{3}(\d|X|x)$/
const zhNamePattern = /^(?:[\u4e00-\u9fa5·]{2,16})$/
return {
zhName:'/^(?:[\u4e00-\u9fa5·]{2,16})$/',
pattern:'/(^\d{8}(0\d|10|11|12)([0-2]\d|30|31)\d{3}$)|(^\d{6}(18|19|20)\d{2}(0\d|10|11|12)([0-2]\d|30|31)\d{3}(\d|X|x)$)/',
ruleForm:{
idCard: '',
name: '',
userId: ''
},
rules: {
name: [
{ pattern: zhNamePattern,trigger: 'blur', required: true, message: '请输入正确的姓名' },
],
idCard: [
{pattern: idCardPattern, message: '请输入正确的身份证号', required: true, trigger: 'blur' },
],
}
}
},
methods:{
onUpdate(){
this.$refs.formRef.validate((valid) => {
if (valid) {
updateIdCard(this.ruleForm).then(res=>{
if(res.code==200){
this.$message.success('认证成功')
this.closeEditInfo()
}
})
}
});
},
closeEditInfo(){
this.$emit('closeNameAuth',false)
}
},
mounted() {
this.ruleForm.userId = this.userId
},
};
</script>
<style scoped lang="scss">
body {
font-family: Arial, sans-serif;
background-color: #f7f9fc;
margin: 0;
padding: 0;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
}
.container{
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background-color: rgba($color: #000000, $alpha: 0.7);
display: flex;
justify-content: center;
align-items: center;
height: calc(100vh - $titleBarHeight);
}
.profile-container {
background: white;
border-radius: 12px;
width: 400px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
padding: 20px;
position: relative;
.tip{
margin-bottom: 20px;
font-size: 12px;
color: #ff0000;
}
// width: 360px;
// padding: 40px;
// background: #fff;
// border-radius: 10px;
// box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}
.profile-form .form-group {
margin-bottom: 15px;
padding: 20px 0;
}
.profile-form label {
font-size: 14px;
font-weight: bold;
display: block;
margin-bottom: 5px;
}
.input-wrapper {
position: relative;
}
.input-wrapper input {
width: 100%;
padding: 10px;
border: 1px solid #d8d8d8;
border-radius: 5px;
font-size: 14px;
}
.input-wrapper .char-count {
position: absolute;
right: 10px;
top: 50%;
transform: translateY(-50%);
font-size: 12px;
color: #888;
}
textarea {
width: 100%;
height: 80px;
padding: 10px;
border: 1px solid #d8d8d8;
border-radius: 5px;
font-size: 14px;
resize: none;
}
.social-links {
display: grid;
gap: 10px;
}
.social-link {
display: flex;
align-items: center;
gap: 10px;
}
.social-link span {
white-space: nowrap;
font-size: 14px;
}
.social-link input {
flex: 1;
padding: 10px;
border: 1px solid #d8d8d8;
border-radius: 5px;
}
.form-buttons {
display: flex;
justify-content: space-between;
margin-top: 20px;
}
.cancel-button,
.submit-button {
flex: 1;
padding: 10px;
border: none;
border-radius: 5px;
cursor: pointer;
font-size: 14px;
margin: 0 5px;
}
.cancel-button {
background-color: #e0e0e0;
}
.submit-button {
background-color: #007bff;
color: white;
}
</style>

View File

@ -0,0 +1,288 @@
<template>
<div class="container">
<i class="el-icon-close close-btn" @click="onCloseLogin(false)"></i>
<div class="upload-container">
<h2>上传我的作品</h2>
<!-- 上传按钮 -->
<div>
<!-- <p class="upload-tip">
建议用图库上传的图片作为封面图获得更多推荐流量和试用用户<br />
最多支持添加8张图片
</p> -->
<div class="upload-buttons">
<button class="upload-btn" @click="selectPictureFromGallery">
本地上传
<input
type="file"
@change="handlePictureChange"
accept="image/*"
ref="pictureInput"
multiple
style="display: none"
/>
</button>
</div>
</div>
<div>
<!-- <img v-for="(item) in params.pictureResultList" :src="item" alt=""> -->
</div>
<div class="publish-img-content">
<img
class="publish-img"
v-for="item in imageFiles"
:src="item"
alt=""
/>
</div>
<el-form
:model="ruleForm"
ref="ruleForm"
label-width="100px"
class="demo-ruleForm"
>
<el-form-item label="图片标题" prop="name">
<el-input v-model="ruleForm.title"></el-input>
</el-form-item>
<el-form-item label="图片标签" prop="name">
<el-select
v-model="ruleForm.tags"
multiple
filterable
style="width: 100%;"
allow-create
default-first-option
placeholder="请选择文章标签"
>
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value"
>
</el-option>
</el-select>
</el-form-item>
<el-form-item label="描述信息" prop="desc">
<el-input :row="8" type="textarea" v-model="ruleForm.desc"></el-input>
</el-form-item>
</el-form>
<!-- 发布按钮 -->
<button class="submit-button" @click="submitForm"></button>
</div>
</div>
</template>
<script>
import { uploadImagesInBatches } from "@/utils/uploadImages.js";
export default {
data() {
return {
imageFiles:[],
options:[],
ruleForm: {
imagePaths: [],
title: "",
tags: "",
description: "",
},
};
},
methods: {
async handlePictureChange(event) {
const files = event.target.files;
if (files.length > 3) {
alert("最多只能选择 3 张图片");
return;
}
this.imageFiles = [];
for (let i = 0; i < files.length; i++) {
const file = files[i];
if (file.type.startsWith("image/")) {
this.imageFiles.push(file);
} else {
alert("请选择有效的图片文件");
}
}
const pictureResultList = await uploadImagesInBatches(this.imageFiles);
this.ruleForm.imagePaths = pictureResultList;
},
onCloseLogin() {
this.$emit("closePublishWorks", false);
},
selectPictureFromGallery() {
this.$refs.pictureInput.click();
},
submitForm() {
if (!this.imagePaths) {
this.$message({
message: '必须上传一张图片!',
type: 'warning'
});
} else {
alert("发布成功!");
}
},
},
};
</script>
<style lang="scss" scoped>
$primary-color: #007bff;
$text-color: #333;
$border-color: #e6e6e6;
$placeholder-color: #999;
.container {
position: fixed;
top: 0;
left: 0;
z-index: 999;
width: 100vw;
height: 100vh;
background-color: rgba($color: #000000, $alpha: 0.7);
display: flex;
justify-content: center;
align-items: center;
.publish-img-content {
display: flex;
flex-wrap: wrap;
box-sizing: border-box;
margin-bottom: 10px;
.publish-img {
padding: 4px;
width: 33.33%;
height: 160px;
border-radius: 8px;
}
}
.close-btn {
position: absolute;
cursor: pointer;
right: 10px;
top: 10px;
color: #fff;
font-size: 30px;
z-index: 999;
}
::-webkit-scrollbar {
display: none; /* 对于 WebKit 浏览器Chrome, Safari */
}
.upload-container {
width: 600px;
padding: 20px;
background: #fff;
border-radius: 10px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
max-height: 90%;
overflow: auto;
h2 {
font-size: 20px;
color: $text-color;
margin-bottom: 20px;
text-align: center;
}
.upload-buttons {
border: 1px solid $border-color;
height: 120px;
background-color: #f3f5f9;
display: flex;
justify-content: center;
margin-bottom: 15px;
align-items: center;
border-radius: 10px;
.upload-btn {
background: $primary-color;
color: #fff;
border: none;
border-radius: 5px;
padding: 10px 15px;
font-size: 16px;
margin: 0 5px;
height: 40px;
cursor: pointer;
transition: background-color 0.3s;
&:hover {
background-color: darken($primary-color, 10%);
}
i {
margin-right: 5px;
}
}
}
.upload-tip {
font-size: 12px;
color: $placeholder-color;
text-align: center;
margin-bottom: 20px;
}
.form-group {
margin-bottom: 20px;
label {
display: block;
font-size: 14px;
color: $text-color;
margin-bottom: 5px;
}
input,
select,
textarea {
width: 100%;
padding: 10px;
border: 1px solid $border-color;
border-radius: 5px;
font-size: 14px;
color: $text-color;
outline: none;
&:focus {
border-color: $primary-color;
box-shadow: 0 0 5px rgba(0, 123, 255, 0.3);
}
&::placeholder {
color: $placeholder-color;
}
}
textarea {
height: 80px;
resize: none;
}
.char-counter {
font-size: 12px;
color: $placeholder-color;
text-align: right;
margin-top: 5px;
}
}
.submit-button {
width: 100%;
background: $primary-color;
color: #fff;
border: none;
border-radius: 5px;
padding: 10px 15px;
font-size: 16px;
cursor: pointer;
transition: background-color 0.3s;
&:hover {
background-color: darken($primary-color, 10%);
}
}
}
}
</style>

View File

@ -0,0 +1,330 @@
<template>
<div class="product-list" ref="listContainer" @scroll="handleScroll">
<div class="image-grid-container">
<!-- 商品卡片网格 -->
<div class="image-grid">
<div class="image-card" v-for="item in products1" :key="item.id">
<div class="image-wrapper">
<img
src="http://img2.baidu.com/it/u=705459853,1015457524&fm=253&app=138&f=JPEG?w=800&h=1422"
:alt="item.title"
/>
</div>
<div class="drop-down">
<i class="el-icon-more">
<div class="drop-down-group">
<div class="drop-down-item" @click="handleEdit(item)"></div>
<div class="drop-down-item delete" @click="handleDelete(item)"></div>
<div class="drop-down-item" @click="handleTop(item)"></div>
</div>
</i>
</div>
<!-- <div class="image-info">
<h3 class="title">{{ item.title }}</h3>
<p class="details">{{ item.details }}</p>
<div class="stats">
<span><i class="icon icon-view"></i>{{ item.views }}</span>
<span><i class="icon icon-like"></i>{{ item.likes }}</span>
<span><i class="icon icon-comment"></i>{{ item.comments }}</span>
</div>
</div> -->
</div>
</div>
</div>
<div v-if="loading" class="loading">...</div>
<div v-if="noMore" class="no-more"></div>
</div>
</template>
<script>
import { mallProduct } from "@/api/mcwl/personalCenter";
import _ from "lodash";
export default {
props: {
order: {
type: String,
default: 0, // 0
},
status: {
type: String,
default: 0, // 0
},
date: {
type: Array | null,
default: [], // []
},
},
watch: {
// status
status: {
// immediate: true,
handler() {
this.resetAndFetchProducts();
},
},
date: {
// immediate: true,
handler() {
this.resetAndFetchProducts();
},
},
order: {
// immediate: true,
handler() {
this.resetAndFetchProducts();
},
},
},
mounted() {
this.fetchProducts();
},
data() {
return {
products1: [{ title: "wewre" }, {}, {},{},{}], // ,
products: [], //
pageNumber: 1, //
pageSize: 12, //
loading: false, //
noMore: false, //
};
},
methods: {
//
throttle(func, delay) {
let lastTime = 0;
return function (...args) {
const now = new Date().getTime();
if (now - lastTime >= delay) {
lastTime = now;
func.apply(this, args);
}
};
},
//
resetAndFetchProducts() {
this.products = [];
this.pageNumber = 1;
this.noMore = false;
this.fetchProducts();
},
//
async fetchProducts() {
if (this.loading || this.noMore) return;
this.loading = true;
try {
let params = {
pageNumber: this.pageNumber,
pageSize: this.pageSize,
status: this.status, // status
order: this.order, // status
// startTime: this.date[0], // status
// endTime: this.date[1], // status
};
if (this.date && this.date.length > 0) {
params.startTime = `${this.date[0]} 00:00:00`;
params.endTime = `${this.date[1]} 23:59:59`;
}
mallProduct(params).then((res) => {
if (res.data.records && res.data.records.length > 0) {
const newProducts = res.data.records;
if (newProducts.length < this.pageSize) {
this.noMore = true; //
}
this.products = [...this.products, ...newProducts];
this.pageNumber += 1; //
}
});
} catch (error) {
console.error("加载商品数据失败:", error);
} finally {
this.loading = false;
}
},
// fetchProducts:throttle(()=>{
// if (this.loading || this.noMore) return;
// this.loading = true;
// try {
// let params = {
// pageNumber: this.pageNumber,
// pageSize: this.pageSize,
// status: this.status, // status
// order: this.order, // status
// }
// mallProduct(params).then((res)=>{
// const newProducts = res.data.records;
// if (newProducts.length < this.pageSize) {
// this.noMore = true; //
// }
// this.products = [...this.products, ...newProducts];
// this.pageNumber += 1; //
// })
// } catch (error) {
// console.error("", error);
// } finally {
// this.loading = false;
// }
// },1000),
//
// handleScroll:throttle(()=>{
// const container = this.$refs.listContainer;
// if (!container) return;
// const scrollTop = container.scrollTop; //
// const scrollHeight = container.scrollHeight; //
// const clientHeight = container.clientHeight; //
// //
// if (scrollTop + clientHeight >= scrollHeight - 10) {
// this.fetchProducts();
// }
// }, 1000),
handleScroll() {
const container = this.$refs.listContainer;
if (!container) return;
const scrollTop = container.scrollTop; //
const scrollHeight = container.scrollHeight; //
const clientHeight = container.clientHeight; //
//
if (scrollTop + clientHeight >= scrollHeight - 10) {
this.fetchProducts();
}
},
},
};
</script>
<style scoped lang="scss">
.product-list {
height: 400px;
overflow-y: auto;
// border: 1px solid #ccc;
padding: 10px;
/* SCSS 样式 */
/* 变量定义 */
$background-color: #f5f5f5;
$card-bg-color: #fff;
$text-color: #333;
$sub-text-color: #555;
$icon-color: #999;
$box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
/* 容器样式 */
.image-grid-container {
// height: 100px;
padding: 20px;
.image-grid {
display: flex;
flex-wrap: wrap;
gap: 16px;
justify-content: flex-start;
}
.image-card {
border-radius: 10px;
position: relative;
height: 300px;
background: $card-bg-color;
// box-shadow: $box-shadow;
overflow: hidden;
width: calc(25% - 16px); // 4
display: flex;
flex-direction: column;
.drop-down {
position: absolute;
top: 10px;
right: 10px;
color: #fff;
cursor: pointer;
.el-icon-more {
&:hover {
.drop-down-group{
display: block;
}
}
.drop-down-group {
position: absolute;
top: 14px;
right: -10px;
background-color: #fff;
border-radius: 10px;
display: none;
.drop-down-item {
width: 100px;
text-align: center;
line-height: 40px;
color: #2f2f2f;
}
.delete{
color: #ff0000;
}
}
}
}
.image-wrapper {
img {
width: 100%;
height: 300px;
display: block;
}
}
.image-info {
padding: 10px;
font-size: 14px;
color: $text-color;
.title {
font-weight: bold;
font-size: 16px;
margin-bottom: 8px;
color: darken($text-color, 10%);
}
.details {
margin-bottom: 8px;
color: $sub-text-color;
}
.stats {
display: flex;
justify-content: space-between;
font-size: 12px;
color: $icon-color;
span {
display: flex;
align-items: center;
gap: 4px;
.icon {
font-size: 14px;
color: $icon-color;
}
}
}
}
}
}
}
.product-item {
margin-bottom: 15px;
padding: 10px;
// border: 1px solid #481212;
border-radius: 5px;
color: #481212;
}
.loading,
.no-more {
text-align: center;
padding: 10px;
color: #999;
}
</style>

View File

@ -0,0 +1,125 @@
<template>
<div class="container">
<!-- Quill 富文本编辑器 -->
<quill-editor
v-model="content"
ref="myQuillEditor"
style="height: 100px"
@input="onInput"
:options="editorOption"
@change="onEditorChange"
/>
<!-- 隐藏的文件上传输入框 -->
<input
type="file"
ref="imageInput"
multiple
style="display: none"
@change="handleImageUpload"
accept="image/*"
/>
</div>
</template>
<script>
import { quillEditor } from "vue-quill-editor";
import "quill/dist/quill.core.css";
import "quill/dist/quill.snow.css";
import "quill/dist/quill.bubble.css";
import { uploadImagesInBatches } from "@/utils/uploadImages.js";
export default {
components: {
quillEditor,
},
data() {
return {
content: "", //
editorOption: {
modules: {
toolbar: {
container: [
["bold", "italic", "underline", "strike"], // 线线
["blockquote", "code-block"], //
[{ header: 1 }, { header: 2 }], //
[{ list: "ordered" }, { list: "bullet" }], //
[{ script: "sub" }, { script: "super" }], //
[{ indent: "-1" }, { indent: "+1" }], //
[{ direction: "rtl" }], //
[{ size: ["small", false, "large", "huge"] }], //
[{ header: [1, 2, 3, 4, 5, 6, false] }], //
[{ color: [] }, { background: [] }], //
[{ font: [] }], //
[{ align: [] }], //
["clean"], //
["link", "image", "video"], //
],
handlers: {
image: this.handleImageClick, //
},
},
},
},
};
},
methods: {
onInput(value) {
this.$emit("input", value);
},
//
onEditorChange({ quill, html, text }) {
this.$emit("input", html);
console.log("编辑器内容:", html);
},
//
handleImageClick() {
this.$refs.imageInput.click(); //
},
//
async handleImageUpload(event) {
const files = event.target.files;
let imageFiles = [];
for (let i = 0; i < files.length; i++) {
const file = files[i];
if (file.type.startsWith("image/")) {
imageFiles.push(file);
// this.imageUrls.push(URL.createObjectURL(file)); // URL
} else {
alert("请选择有效的图片文件");
}
}
const res = await uploadImagesInBatches(imageFiles);
// const quill = this.$refs.myQuillEditor.quill;
// const range = quill.getSelection();
// quill.insertEmbed(range.index, "image", res[0]); //
// if (file) {
// const formData = new FormData();
// formData.append("image", file);
// //
// fetch("https://your-image-upload-api.com/upload", {
// method: "POST",
// body: formData,
// })
// .then((response) => response.json())
// .then((data) => {
// const quill = this.$refs.myQuillEditor.quill;
// const range = quill.getSelection();
// quill.insertEmbed(range.index, "image", data.imageUrl); //
// })
// .catch((error) => {
// console.error("", error);
// });
// }
},
},
};
</script>
<style scoped>
.container {
background-color: #fff;
height: 166px;
}
/* 自定义样式 */
</style>

View File

@ -0,0 +1,352 @@
<template>
<div class="container">
<div class="content">
<div class="left-content">
<el-form
class="form-content"
:model="formData"
:rules="rules"
ref="formFef"
label-width="120px"
label-position="top"
>
<el-form-item prop="modelName">
<div class="form-title">工作流名称<span class="form-required">*</span></div>
<el-input v-model="formData.name1" placeholder="请输入工作流名称"></el-input>
</el-form-item>
<!-- 内容类别 -->
<el-form-item prop="category">
<div class="form-title">内容类别</div>
<div class="form-desc">
填写类别可让模型获得更精准的流量, 平台也有权基于标准修改你的类别标签
</div>
<el-cascader
class="formWidth"
placeholder="垂类"
:props="{
label: 'dictLabel', // label
value: 'dictValue', // value
children: 'children', // children
}"
v-model="formData.category"
:options="options1"
:show-all-levels="true"
></el-cascader>
<el-select
style="margin-top: 4px"
class="formWidth"
v-model="formData.work_flow_functions"
placeholder="主体"
clearable
>
<el-option
v-for="item in work_flow_functions"
:key="item.dictValue"
:label="item.dictLabel"
:value="item.dictValue"
></el-option>
</el-select>
<el-select
style="margin-top: 4px"
class="formWidth"
v-model="formData.work_flow_functions"
placeholder="风格"
clearable
>
<el-option
v-for="item in work_flow_functions"
:key="item.dictValue"
:label="item.dictLabel"
:value="item.dictValue"
></el-option>
</el-select>
<el-select
style="margin-top: 4px"
class="formWidth"
v-model="formData.work_flow_functions"
placeholder="功能"
clearable
>
<el-option
v-for="item in work_flow_functions"
:key="item.dictValue"
:label="item.dictLabel"
:value="item.dictValue"
></el-option>
</el-select>
</el-form-item>
<!-- 参与活动 -->
<el-form-item prop="activity">
<div class="form-title">参与活动</div>
<div class="form-desc">参加特定活动或比赛, 下拉选择</div>
<el-select
class="formWidth"
v-model="formData.activity"
placeholder="请选择参与活动"
clearable
>
<el-option
v-for="item in activities"
:key="item.dictValue"
:label="item.dictLabel"
:value="item.dictValue"
></el-option>
</el-select>
</el-form-item>
</el-form>
</div>
<div class="right-content">
<div class="form-wrapper">
<el-form
:model="formData"
:rules="rules"
label-width="120px"
label-position="top"
>
<div class="mcwl-stack-root stepOne">
<div>
<div class="form-desc">是否公开</div>
<div class="FormField_content">
<div class="ant-segmented-group">
<div
class="ant-segmented-group-item"
v-for="(item, index) in originalBtnList"
:key="index"
@click="formData.content = item.value"
:style="{
backgroundColor:
formData.content === item.value
? 'rgba(49, 98, 255, 0.1)'
: '#fff',
color: formData.content === item.value ? '#3162ff' : '#000',
}"
>
{{ item.label }}
</div>
</div>
</div>
</div>
<div>
<div class="form-title">是否原创</div>
<div class="FormField_content">
<div class="ant-segmented-group">
<div
class="ant-segmented-group-item"
v-for="(item, index) in originalBtnList"
:key="index"
@click="formData.content = item.value"
:style="{
backgroundColor:
formData.content === item.value
? 'rgba(49, 98, 255, 0.1)'
: '#fff',
color: formData.content === item.value ? '#3162ff' : '#000',
}"
>
{{ item.label }}
</div>
</div>
</div>
</div>
</div>
<div class="mcwl-stack-root stepTwo">
<div>
<div style="color: #3162ff; margin-bottom: 10px">
用户使用时, 我授予用户以下权限:
</div>
<el-checkbox-group v-model="formData.type">
<el-checkbox label="允许在线使用" name="type"></el-checkbox>
</el-checkbox-group>
<div
style="
color: #999999;
margin: 4px 0 10px 0;
padding-left: 24px;
font-size: 12px;
"
>
您的工作流为公开状态时, 默认同意此条款, 他人不能随意转载
</div>
<el-checkbox-group v-model="formData.type">
<el-checkbox label="允许下载工作流" name="type"></el-checkbox>
</el-checkbox-group>
<div
style="
color: #999999;
margin: 4px 0 10px 0;
padding-left: 24px;
font-size: 12px;
"
>
允许下载后, 您的工作流可能会被 他人转载, 我们无法控制该行为
</div>
</div>
<div>
<div style="color: #3162ff; margin-bottom: 10px">
用户使用时, 我授予用户以下商业用途权限:
</div>
<el-checkbox-group v-model="formData.type">
<el-checkbox label="" name="type">
生成图片可出售或者用于商业目的
</el-checkbox>
</el-checkbox-group>
</div>
<div>
<div style="margin: 20px 0 10px 0">声明</div>
<div class="explain" style="font-size: 12px">
<div>请勿转载境外模型</div>
<div>请勿上传色情暴力等违法内容</div>
<div>不得侵害他人依法享有的知识产权</div>
<div>您所上传的内容需要使用具有合法来源的数据</div>
<div>魔创未来将会对上传的所有内容进行安全审查</div>
<div>许可范围为创作者本人设置, 使用者需要按规范使用</div>
</div>
</div>
</div>
</el-form>
</div>
</div>
</div>
<div class="mcwl-stack-footer">
<div class="next-step" @click="onNextStep"></div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
originalBtnList: [
{
label: "原创",
value: "original",
},
{
label: "非原创",
value: "notOriginal",
},
],
rules: {},
activities: [],
work_flow_functions: [],
options1: [],
formData: {
name: "",
content: "original",
type: "",
tags: "",
name1: "",
},
};
},
methods: {
onNextStep(){
this.$emit('changeWorkFlowInfo',this.formData)
this.$emit('nextStep',2)
}
}
};
</script>
<style lang="scss" scoped>
.container {
.content {
display: flex;
.left-content {
.form-title {
// font-weight: 600;
color: #000;
.form-required {
color: red;
}
}
.form-desc {
color: #999;
font-size: 12px;
line-height: 10px;
margin-bottom: 8px;
}
.formWidth {
width: 100%;
}
width: 66%;
background: #f4f5f9;
padding: 20px;
border-radius: 10px;
margin-right: 20px;
}
.right-content {
width: 33%;
.form-wrapper {
.mcwl-stack-root {
margin-bottom: 10px;
background: #f4f5f9;
padding: 20px;
border-radius: 10px;
.explain {
> div {
padding: 4px 0;
color: #999;
}
}
}
.stepTwo {
font-size: 14px;
}
.FormField_content {
width: 100%;
height: 30px;
margin: 10px 0;
background-color: #fff;
border-radius: 4px;
.form-title {
color: #000;
}
.ant-segmented-group {
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
height: 100%;
.ant-segmented-group-item {
width: 50%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
border-radius: 4px;
}
}
}
}
width: 34%;
// background: #f4f5f9;
// padding: 20px;
// border-radius: 10px;
}
}
.mcwl-stack-footer {
display: flex;
justify-content: flex-end;
.next-step {
width: 100px;
height: 40px;
line-height: 40px;
text-align: center;
background: #3162ff;
color: #fff;
border-radius: 4px;
cursor: pointer;
}
}
}
</style>

View File

@ -0,0 +1,243 @@
<template>
<div class="container">
<input
type="file"
@change="handleFileChange"
accept="image/*"
ref="pictureInput"
style="display: none"
/>
<div class="header">
<div class="header-group">
<div class="add-version" @click="addForm"></div>
<!-- <div>收起版本信息</div> -->
</div>
<div class="header-tips">小提醒: 版本在当前页面展示顺序为线上用户实际看到顺序</div>
</div>
<div class="form-group">
<div v-for="(form, index) in forms" :key="index" class="form-wrapper">
<div class="version-form-group">
<div class="">
<i @click="removeForm(index)" class="el-icon-delete" :size="28"></i>
</div>
</div>
<el-form
:model="form"
:ref="`form${index}`"
:rules="rules"
label-width="120px"
label-position="top"
>
<el-form-item prop="name">
<div class="form-title">版本名称<span class="form-required">*</span></div>
<el-input v-model="form.name" placeholder="请输入名称"></el-input>
</el-form-item>
<el-form-item prop="type">
<div class="form-upload-img">
<div class="form-title">上传工作流文件<span class="form-required">*</span></div>
<div v-if="form.file"><span>100%</span>这是一个文件名</div>
<div v-else class="upload-img-container">
<div class="upload-img-btn" @click="onUploadFile(index)"></div>
<!-- <div>拖拽文件</div> -->
<div class="upload-img-tips">支持格式.json/.zip</div>
</div>
</div>
</el-form-item>
</el-form>
</div>
<div class="step-group">
<div class="step1-group">
<div
class="step-btn step1"
style="background-color: #f1f2f7; color: #000; margin-right: 20px"
@click="onStepNext(1)"
>
上一步
</div>
<div class="step-btn step1" @click="onStepNext(3)"></div>
</div>
</div>
</div>
</div>
</template>
<script>
import { uploadImagesInBatches } from "@/utils/uploadImages.js";
export default {
data() {
return {
currentUploadIndex:null,
forms: [
{
name: "",
type: "",
file: "",
editorContent: "",
},
],
rules: {
name: [{ required: true, message: "请输入名称", trigger: "blur" }],
},
};
},
methods: {
addForm() {
this.forms.push({
name1: "",
type: "",
file: "",
editorContent: "",
});
},
removeForm(index) {
if(this.forms.length === 1) return
this.forms.splice(index, 1);
},
//
onStepNext(index) {
if (index == 3) {
let allValid = true;
this.forms.forEach((form, index) => {
this.$refs[`form${index}`][0].validate((valid) => {
if (!valid) {
allValid = false;
}
});
});
if (allValid) {
this.$emit("stepNext", index);
this.$emit("changeEditVersionWorkFlowInfo", this.forms);
//
} else {
console.log("表单验证未通过");
}
} else if (index == 1) {
this.$emit("stepNext", index);
}
},
onUploadFile(index) {
this.currentUploadIndex = index;
this.$refs.pictureInput.click();
},
//
async handleFileChange(event) {
console.log("object", event);
const files = event.target.files;
if (files.length > 1) {
alert("只能选择 1 张图片");
return;
}
let imageFiles = [];
for (let i = 0; i < files.length; i++) {
const file = files[i];
if (file.type.startsWith("image/")) {
imageFiles.push(file);
// this.imageUrls.push(URL.createObjectURL(file)); // URL
} else {
alert("请选择有效的图片文件");
}
}
const pictureResultList = await uploadImagesInBatches(imageFiles);
let imgUrl = pictureResultList.join(',')
this.forms[this.currentUploadIndex].file = imgUrl
},
},
};
</script>
<style lang="scss" scoped>
.container {
font-size: 14px;
.header {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
.header-tips {
color: #b1b1b1;
font-size: 12px;
margin: 20px 0;
}
.header-group {
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: center;
.add-version {
cursor: pointer;
width: 200px;
line-height: 40px;
font-weight: 600;
border-radius: 30px;
border: 1px solid #b1b1b1;
text-align: center;
}
}
}
.form-group {
.form-wrapper {
background-color: #f4f5f9;
padding: 20px;
border-radius: 10px;
position: relative;
margin-bottom: 20px;
.version-form-group {
position: absolute;
right: -20px;
cursor: pointer;
top: 0px;
}
.form-title{
.form-required{
color: red;
}
}
.upload-img-container {
width: 100%;
height: 150px;
border: 1px dashed #ccc;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
background-color: #fff;
border-radius: 10px;
.upload-img-btn {
padding: 4px 20px;
text-align: center;
background-color: rgb(45, 40, 255);
color: #fff;
border-radius: 4px;
cursor: pointer;
}
.upload-img-tips {
font-size: 12px;
color: #999;
margin-top: 10px;
}
}
}
.step-group {
margin-top: 20px;
display: flex;
align-items: center;
justify-content: center;
.step-btn {
width: 200px;
height: 40px;
text-align: center;
line-height: 40px;
}
.step1-group {
display: flex;
background-color: blue;
border-radius: 4px;
color: #fff;
cursor: pointer;
}
}
}
}
</style>

View File

@ -0,0 +1,261 @@
<template>
<div class="container">
<div class="pay-content">
<div class="header-user-info">
<div class="user-info">
<div class="user-avatar">
<img src="../../assets/images/wechat.png" alt="" />
</div>
<div class="user-group">
<div class="user-name">微信用户a932432</div>
<div class="user-level">
<div class="user-level-icon">
<svg-icon icon-class="userCenter"></svg-icon>
</div>
<div class="user-level-name">您还不是魔创未来的会员</div>
</div>
</div>
</div>
<div class="close-icon" @click="closeVipPay">X</div>
</div>
<div class="vip-card">
<div class="vip-card-item">
<div class="vip-card-item-title">
<svg-icon icon-class="userCenter"></svg-icon>
基础版VIP连续包月
</div>
<div class="price">
<div class="price-symbol">¥</div>
<div class="price-number">9.9</div>
<div class="original-price">¥19.9</div>
</div>
<div class="price-desc">次月续费¥39</div>
</div>
<div class="vip-card-item">
<div class="vip-card-item-title">
<svg-icon icon-class="userCenter"></svg-icon>
基础版VIP连续包月
</div>
<div class="price">
<div class="price-symbol">¥</div>
<div class="price-number">9.9</div>
<div class="original-price">¥19.9</div>
</div>
<div class="price-desc">次月续费¥39</div>
</div>
<div class="vip-card-item">
<div class="vip-card-item-title">
<svg-icon icon-class="userCenter"></svg-icon>
基础版VIP连续包月
</div>
<div class="price">
<div class="price-symbol">¥</div>
<div class="price-number">9.9</div>
<div class="original-price">¥19.9</div>
</div>
<div class="price-desc">次月续费¥39</div>
</div>
<div class="vip-card-item">
<div class="vip-card-item-title">
<svg-icon icon-class="userCenter"></svg-icon>
基础版VIP连续包月
</div>
<div class="price">
<div class="price-symbol">¥</div>
<div class="price-number">9.9</div>
<div class="original-price">¥19.9</div>
</div>
<div class="price-desc">次月续费¥39</div>
</div>
<!-- <div class="vip-card-item">
<div class="vip-card-item-title">
<svg-icon icon-class="userCenter"></svg-icon>
基础版VIP连续包月
</div>
<div class="price">
<div class="price-symbol">¥</div>
<div class="price-number">9.9</div>
<div class="original-price">¥19.9</div>
</div>
<div class="price-desc">次月续费¥39</div>
</div> -->
</div>
<div class="vip-list-container">
<div class="vip-list-item">
<div class="vip-list-subitem">
<svg-icon icon-class="userCenter"></svg-icon>
基础版VIP权益
</div>
<div class="vip-list-subitem">每月15000点算力</div>
<div class="vip-list-subitem">每月20GB存储空间</div>
<div class="vip-list-subitem">每月800次生图加速</div>
<div class="vip-list-subitem">2个生图任务并行</div>
<div class="vip-list-subitem">-</div>
</div>
<div class="vip-list-item">
<div class="vip-list-subitem">
<svg-icon icon-class="userCenter"></svg-icon>
专业版VIP权益
</div>
<div class="vip-list-subitem">每月35000点算力</div>
<div class="vip-list-subitem">每月50GB存储空间</div>
<div class="vip-list-subitem">每月5000次生图加速</div>
<div class="vip-list-subitem">3个生图任务并行</div>
<div class="vip-list-subitem">可训练XL模型</div>
</div>
</div>
<div class="vip-list-desc">
会员每月算力和加速特权按下月下发, 有效期31天, 到期重置
</div>
<div class="pay-container">
<div class="pay-qrcode">
</div>
<div class="pay-info">
<div class="pay-info-title">
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'vipPay',
data() {
return {}
},
methods: {
closeVipPay(){
this.$emit('closeVipPay')
}
},
mounted() {},
}
</script>
<style lang="scss" scoped>
.container {
color: #333;
position: fixed;
background-color: rgba($color: #000000, $alpha: 0.5);
width: 100%;
height: 100%;
top: 0;
left: 0;
z-index: 9999;
display: flex;
align-items: center;
justify-content: center;
.pay-content {
background-color: #fff;
border-radius: 20px;
.header-user-info {
padding:10px 20px;
border-radius: 20px 20px 0 0;
background-color: #ffda96;
display: flex;
align-items: center;
justify-content: space-between;
.user-info {
display: flex;
align-items: center;
justify-content: center;
.user-avatar {
margin-right: 20px;
border-radius: 50%;
background-color: #ccc;
}
.user-group {
display: flex;
flex-direction: column;
justify-content: space-around;
.user-name {
font-size: 16px;
font-weight: bold;
color: #333;
}
.user-level {
display: flex;
align-items: center;
.user-level-name {
color: #333;
font-size: 12px;
}
}
}
}
.close-icon {
}
}
.vip-card {
padding: 10px 30px;
display: flex;
gap: 10px;
.vip-card-item {
width: 170px;
height: 152px;
background: linear-gradient(90deg, #fffaf1, #ffeccf);
border-radius: 10px;
border: 1px solid #f7b252;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-around;
.vip-card-item-title{
display: flex;
align-items: center;
justify-content: center;
font-size: 12px;
color: #814600;
}
.price{
display: flex;
.price-symbol{
color: #814600;
font-size: 14px;
margin-right: 4px;
}
.price-number{
color: #814600;
font-size: 20px;
margin-right: 4px;
}
.original-price{
text-decoration: line-through;
}
}
}
}
.vip-list-container {
padding: 10px 30px;
.vip-list-item {
width: 100%;
display: flex;
.vip-list-subitem {
// white-space: nowrap;
width: 140px;
border: 1px solid #eeeeee;
flex: 1;
line-height: 30px;
text-align: center;
font-size: 12px;
color: #333;
padding: 10px;
}
}
}
.vip-list-desc{
padding:0 30px;
color: #9d8c75;
font-size: 12px;
line-height: 18px;
margin-top: 6px;
}
}
}
</style>

View File

@ -0,0 +1,223 @@
<template>
<div class="membership-table">
<h2 class="title">会员权益</h2>
<div class="plans-container">
<!-- 会员等级列 -->
<div class="plan-column features">
<div class="plan-header">会员权益</div>
<div class="feature-item" v-for="feature in features" :key="feature">
{{ feature }}
</div>
</div>
<!-- 免费用户列 -->
<div class="plan-column free">
<div class="plan-header">免费用户</div>
<div class="plan-details">
<div class="feature-item">每天300点</div>
<div class="feature-item">3GB</div>
<div class="feature-item">
<span class="cross"></span>
</div>
<div class="feature-item">
<span class="cross"></span>
</div>
<div class="feature-item">
<span class="cross"></span>
</div>
<div class="feature-item">
<span class="cross"></span>
</div>
<div class="feature-item">
<span class="cross"></span>
</div>
<div class="feature-item">
<span class="cross"></span>
</div>
</div>
</div>
<!-- 基础版VIP列 -->
<div class="plan-column basic">
<div class="plan-header">
<span class="vip-icon">💎</span>
基础版VIP
</div>
<div class="plan-details">
<div class="feature-item">每月15000点</div>
<div class="feature-item">20GB</div>
<div class="feature-item">每月800次</div>
<div class="feature-item">
<span class="check"></span>
</div>
<div class="feature-item">
<span class="check"></span>
</div>
<div class="feature-item">
<span class="cross"></span>
</div>
<div class="feature-item">
<span class="check"></span>
</div>
<div class="feature-item">2</div>
</div>
</div>
<!-- 专业版VIP列 -->
<div class="plan-column pro">
<div class="plan-header">
<span class="vip-icon">💝</span>
专业版VIP
</div>
<div class="plan-details">
<div class="feature-item">每月35000点</div>
<div class="feature-item">50GB</div>
<div class="feature-item">每月5000次</div>
<div class="feature-item">
<span class="check"></span>
</div>
<div class="feature-item">
<span class="check"></span>
</div>
<div class="feature-item">
<span class="check"></span>
</div>
<div class="feature-item">
<span class="check"></span>
</div>
<div class="feature-item">3</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'MembershipTable',
data() {
return {
features: [
'算力',
'云端存储空间',
'生图加速特权',
'会员专属模型',
'生图高级功能',
'训练XL模型',
'图片去水印下载',
'多任务并行生图'
]
}
}
}
</script>
<style lang="scss" scoped>
.membership-table {
padding: 20px;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
color: #6b6a6a;
.title {
text-align: center;
color: #333;
margin-bottom: 30px;
font-size: 24px;
position: relative;
&::before,
&::after {
content: '+';
color: #ffa500;
position: absolute;
top: 50%;
transform: translateY(-50%);
font-size: 20px;
}
&::before {
left: calc(50% - 100px);
}
&::after {
right: calc(50% - 100px);
}
}
.plans-container {
display: flex;
gap: 2px;
background: #f5f5f5;
border-radius: 8px;
overflow: hidden;
}
.plan-column {
flex: 1;
background: white;
&.features {
background: #f8f8f8;
}
&.pro {
background: #fff9f0;
}
}
.plan-header {
padding: 20px;
text-align: center;
font-weight: bold;
background: #fbfbfb;
border-bottom: 1px solid #eee;
.vip-icon {
margin-right: 5px;
}
}
.feature-item {
padding: 15px 20px;
border-bottom: 1px solid #eee;
display: flex;
align-items: center;
justify-content: center;
min-height: 52px;
.check {
color: #4CAF50;
font-size: 20px;
}
.cross {
color: #ff4444;
font-size: 20px;
}
}
.basic {
.plan-header {
color: #ffa500;
}
}
.pro {
.plan-header {
color: #ff6b6b;
}
}
}
@media (max-width: 768px) {
.membership-table {
.plans-container {
flex-direction: column;
}
.feature-item {
padding: 10px;
}
}
}
</style>

5
src/eventBus.js 100644
View File

@ -0,0 +1,5 @@
import Vue from 'vue';
const eventBus = new Vue();
export default eventBus;

View File

@ -1,5 +1,5 @@
<template>
<div :class="classObj" class="app-wrapper" :style="{'--current-color': theme}">
<!-- <div :class="classObj" class="app-wrapper" :style="{'--current-color': theme}">
<div v-if="device==='mobile'&&sidebar.opened" class="drawer-bg" @click="handleClickOutside"/>
<sidebar v-if="!sidebar.hide" class="sidebar-container"/>
<div :class="{hasTagsView:needTagsView,sidebarHide:sidebar.hide}" class="main-container">
@ -12,27 +12,54 @@
<settings/>
</right-panel>
</div>
</div> -->
<div class="container">
<div class="header">
<McHeader></McHeader>
</div>
<div class="content">
<div class="sidebar-content">
<McSidebar @handleRoute="handleRoute"></McSidebar>
</div>
<div class="main-content">
<router-view />
</div>
</div>
</div>
</template>
<script>
import RightPanel from '@/components/RightPanel'
import { AppMain, Navbar, Settings, Sidebar, TagsView } from './components'
import ResizeMixin from './mixin/ResizeHandler'
// import { isRelogin } from '../../utils/request'
import { getToken } from '@/utils/auth'
// import RightPanel from '@/components/RightPanel'
import McHeader from '@/components/McHeader'
import McSidebar from '@/components/McSideBar'
import McLogin from '@/components/McLogin'
import McPersonalCenter from '@/views/McPersonalCenter'
// import { AppMain, Navbar, Settings, Sidebar, TagsView } from './components'
// import ResizeMixin from './mixin/ResizeHandler'
import { mapState } from 'vuex'
import variables from '@/assets/styles/variables.scss'
export default {
name: 'Layout',
components: {
AppMain,
Navbar,
RightPanel,
Settings,
Sidebar,
TagsView
data() {
return {
isShowLogin:false,
}
},
mixins: [ResizeMixin],
components: {
// AppMain,
// Navbar,
// RightPanel,
// Settings,
// Sidebar,
// TagsView,
McHeader,
McSidebar,
McLogin,
McPersonalCenter
},
// mixins: [ResizeMixin],
computed: {
...mapState({
theme: state => state.settings.theme,
@ -55,57 +82,101 @@ export default {
}
},
methods: {
handleClickOutside() {
this.$store.dispatch('app/closeSideBar', { withoutAnimation: false })
}
}
handleRoute(route){
this.$router.push(route)
},
// import Vue from "vue";
// Vue.prototype.$eventBus.$emit("showLogin");
// onCloseLogin(ag){
// this.isShowLogin = ag
// },
// handleClickOutside() {
// this.$store.dispatch('app/closeSideBar', { withoutAnimation: false })
// }
},
mounted() {
// this.isShowLogin = isRelogin.show
},
}
</script>
<style lang="scss" scoped>
@import "~@/assets/styles/mixin.scss";
@import "~@/assets/styles/variables.scss";
.container{
.header{
width: 100%;
height: 60px;
}
.content{
position: relative;
display: flex;
// padding-top: 61px;
.main-content{
flex: 1;
overflow: auto; /* 内容可滚动 */
scrollbar-width: none; /* 仅适用于 Firefox隐藏滚动条 */
-ms-overflow-style: none; /* 仅适用于 IE 和 Edge */
color: #4e4e4e;
// width: 220px;
height: calc(100vh - 61px);
// border-right:1px solid #e7e7e7;
}
.sidebar-content{
.app-wrapper {
@include clearfix;
position: relative;
height: 100%;
width: 100%;
&.mobile.openSidebar {
position: fixed;
top: 0;
}
.login-content{
position: absolute;
top: 0;
left: 0;
flex: 1;
}
}
}
// .main-content{
// display: flex;
// padding-top: 61px
// }
// .app-wrapper {
// @include clearfix;
// position: relative;
// height: 100%;
// width: 100%;
.drawer-bg {
background: #000;
opacity: 0.3;
width: 100%;
top: 0;
height: 100%;
position: absolute;
z-index: 999;
}
// &.mobile.openSidebar {
// position: fixed;
// top: 0;
// }
// }
.fixed-header {
position: fixed;
top: 0;
right: 0;
z-index: 9;
width: calc(100% - #{$base-sidebar-width});
transition: width 0.28s;
}
// .drawer-bg {
// background: #000;
// opacity: 0.3;
// width: 100%;
// top: 0;
// height: 100%;
// position: absolute;
// z-index: 999;
// }
.hideSidebar .fixed-header {
width: calc(100% - 54px);
}
// .fixed-header {
// position: fixed;
// top: 0;
// right: 0;
// z-index: 9;
// // width: calc(100% - #{$base-sidebar-width});
// transition: width 0.28s;
// }
.sidebarHide .fixed-header {
width: 100%;
}
// .hideSidebar .fixed-header {
// width: calc(100% - 54px);
// }
.mobile .fixed-header {
width: 100%;
}
// .sidebarHide .fixed-header {
// width: 100%;
// }
// .mobile .fixed-header {
// width: 100%;
// }
</style>

View File

@ -1,5 +1,5 @@
import Vue from 'vue'
// import App from "./App.vue";
import Cookies from 'js-cookie'
import Element from 'element-ui'
@ -24,7 +24,7 @@ import Pagination from "@/components/Pagination";
// 自定义表格工具组件
import RightToolbar from "@/components/RightToolbar"
// 富文本组件
import Editor from "@/components/Editor"
// import Editor from "@/components/Editor"
// 文件上传组件
import FileUpload from "@/components/FileUpload"
// 图片上传组件
@ -53,7 +53,7 @@ Vue.prototype.handleTree = handleTree
Vue.component('DictTag', DictTag)
Vue.component('Pagination', Pagination)
Vue.component('RightToolbar', RightToolbar)
Vue.component('Editor', Editor)
// Vue.component('Editor', Editor)
Vue.component('FileUpload', FileUpload)
Vue.component('ImageUpload', ImageUpload)
Vue.component('ImagePreview', ImagePreview)
@ -77,7 +77,11 @@ Vue.use(Element, {
})
Vue.config.productionTip = false
// 创建全局事件总线
Vue.prototype.$eventBus = new Vue();
// new Vue({
// render: (h) => h(App),
// }).$mount("#app");
new Vue({
el: '#app',
router,

View File

@ -1,4 +1,5 @@
import router from './router'
import eventBus from './eventBus';
import store from './store'
import { Message } from 'element-ui'
import NProgress from 'nprogress'
@ -26,35 +27,64 @@ router.beforeEach((to, from, next) => {
} else if (isWhiteList(to.path)) {
next()
} else {
if (store.getters.roles.length === 0) {
isRelogin.show = true
// 判断当前用户是否已拉取完user_info信息
// next()
store.dispatch('GetInfo').then(() => {
isRelogin.show = false
// isRelogin.show = false
store.dispatch('GenerateRoutes').then(accessRoutes => {
// 根据roles权限生成可访问的路由表
router.addRoutes(accessRoutes) // 动态添加可访问路由表
next({ ...to, replace: true }) // hack方法 确保addRoutes已完成
// router.addRoutes(accessRoutes) // 动态添加可访问路由表
next() // hack方法 确保addRoutes已完成
})
}).catch(err => {
store.dispatch('LogOut').then(() => {
Message.error(err)
next({ path: '/' })
})
})
} else {
// store.dispatch('LogOut').then(() => {
// Message.error(err)
// next({ path: '/' })
// })
next()
}
})
// if (store.getters.roles.length === 0) {
// isRelogin.show = true
// // 判断当前用户是否已拉取完user_info信息
// store.dispatch('GetInfo').then(() => {
// isRelogin.show = false
// store.dispatch('GenerateRoutes').then(accessRoutes => {
// // 根据roles权限生成可访问的路由表
// router.addRoutes(accessRoutes) // 动态添加可访问路由表
// next({ ...to, replace: true }) // hack方法 确保addRoutes已完成
// })
// }).catch(err => {
// store.dispatch('LogOut').then(() => {
// Message.error(err)
// next({ path: '/' })
// })
// })
// } else {
// next()
// }
}
} else {
// 没有token
if (isWhiteList(to.path)) {
// 在免登录白名单,直接进入
store.dispatch('LogOut').then(() => {
// Message.error(err)
next()
} else {
next(`/login?redirect=${encodeURIComponent(to.fullPath)}`) // 否则全部重定向到登录页
NProgress.done()
}
})
// eventBus.$eventBus.$emit("showLogin");
// const app = Vue
// setTimeout(() => {
// if(app.$eventBus){
// app.$eventBus.$emit("showLogin");
// }
// }, 500);
// 没有token
// if (isWhiteList(to.path)) {
// // 在免登录白名单,直接进入
// next()
// } else {
// next(`/login?redirect=${encodeURIComponent(to.fullPath)}`) // 否则全部重定向到登录页
// NProgress.done()
// }
}
})

View File

@ -62,16 +62,47 @@ export const constantRoutes = [
hidden: true
},
{
path: '',
path: '/',
component: Layout,
redirect: 'index',
name: 'Layout',
redirect: 'home',
children: [
{
path: 'index',
path: '/personalCenter',
component: () => import('@/views/McPersonalCenter/index'),
name: 'PersonalCenter',
meta: { title: '个人中心', icon: 'dashboard', affix: true }
},
{
path: '/home',
component: () => import('@/views/home/index'),
name: 'Home',
meta: { title: '首页', icon: 'dashboard', affix: true }
},
{
path: '/workFlow',
component: () => import('@/views/workFlow/index'),
name: 'WorkFlow',
meta: { title: '工作流', icon: 'dashboard', affix: true }
},
{
path: '/publishModel',
component: () => import('@/views/publishModel/index'),
name: 'PublishModel',
meta: { title: '首页', icon: 'dashboard', affix: true }
},
{
path: '/index',
component: () => import('@/views/index'),
name: 'Index',
meta: { title: '首页', icon: 'dashboard', affix: true }
}
},
{
path: '/vipCenter',
component: () => import('@/views/vipCenter/index'),
name: 'VipCenter',
meta: { title: '首页', icon: 'dashboard', affix: true }
},
]
},
{

View File

@ -5,9 +5,15 @@ const getters = {
dict: state => state.dict.dict,
visitedViews: state => state.tagsView.visitedViews,
cachedViews: state => state.tagsView.cachedViews,
userInfo: state => state.userInfo,
token: state => state.user.token,
idName: state => state.user.idName,
avatar: state => state.user.avatar,
userId: state => state.user.userId,
brief: state => state.user.brief,
userInfo: state => state.user.userInfo,
name: state => state.user.name,
nickName: state => state.user.nickName,
introduction: state => state.user.introduction,
roles: state => state.user.roles,
permissions: state => state.user.permissions,

View File

@ -1,4 +1,6 @@
import { login, logout, getInfo } from '@/api/login'
// import { login, logout, getInfo } from '@/api/login'
import { logout, getInfo } from '@/api/login'
import { login } from '@/api/mcwl/login'
import { getToken, setToken, removeToken } from '@/utils/auth'
import { isHttp, isEmpty } from "@/utils/validate"
import defAva from '@/assets/images/profile.jpg'
@ -6,10 +8,15 @@ import defAva from '@/assets/images/profile.jpg'
const user = {
state: {
token: getToken(),
user:{},
nickName:'',
id: '',
userId: '',
brief: '',
name: '',
avatar: '',
roles: [],
idName:'',
permissions: []
},
@ -17,15 +24,30 @@ const user = {
SET_TOKEN: (state, token) => {
state.token = token
},
SET_USER_INFO: (state, user) => {
state.user = user
},
SET_ID: (state, id) => {
state.id = id
},
SET_USERID: (state, userId) => {
state.userId = userId
},
SET_NAME: (state, name) => {
state.name = name
},
SET_ID_NAME: (state, idName) => {
state.idName = idName
},
SET_NICK_NAME: (state, name) => {
state.nickName = name
},
SET_AVATAR: (state, avatar) => {
state.avatar = avatar
},
SET_BRIEF: (state, brief) => {
state.brief = brief
},
SET_ROLES: (state, roles) => {
state.roles = roles
},
@ -37,15 +59,19 @@ const user = {
actions: {
// 登录
Login({ commit }, userInfo) {
const username = userInfo.username.trim()
const password = userInfo.password
// const username = userInfo.username.trim()
// const password = userInfo.password
const code = userInfo.code
const uuid = userInfo.uuid
const phone = userInfo.phone.trim()
// const uuid = userInfo.uuid
return new Promise((resolve, reject) => {
login(username, password, code, uuid).then(res => {
// username, password, code, uuid
login(phone,code).then(res => {
console.log('object', res);
setToken(res.token)
commit('SET_TOKEN', res.token)
resolve()
this.GetInfo()
}).catch(error => {
reject(error)
})
@ -56,19 +82,24 @@ const user = {
GetInfo({ commit, state }) {
return new Promise((resolve, reject) => {
getInfo().then(res => {
const user = res.user
const user = res.data
let avatar = user.avatar || ""
if (!isHttp(avatar)) {
avatar = (isEmpty(avatar)) ? defAva : process.env.VUE_APP_BASE_API + avatar
}
if (res.roles && res.roles.length > 0) { // 验证返回的roles是否是一个非空数组
commit('SET_ROLES', res.roles)
commit('SET_PERMISSIONS', res.permissions)
} else {
commit('SET_ROLES', ['ROLE_DEFAULT'])
}
commit('SET_ID', user.userId)
// if (res.roles && res.roles.length > 0) { // 验证返回的roles是否是一个非空数组
// commit('SET_ROLES', res.roles)
// commit('SET_PERMISSIONS', res.permissions)
// } else {
// commit('SET_ROLES', ['ROLE_DEFAULT'])
// }
commit('SET_USER_INFO', user)
commit('SET_ID', user.id)
commit('SET_USERID', user.userId)
commit('SET_BRIEF', user.brief)
commit('SET_NAME', user.userName)
commit('SET_NICK_NAME', user.nickName)
commit('SET_ID_NAME', user.name)
commit('SET_AVATAR', avatar)
resolve(res)
}).catch(error => {

View File

@ -0,0 +1,24 @@
// src/utils/downloadImage.js
export async function downloadImage(imageUrl, fileName = 'downloaded_image.jpg') {
try {
// 使用 fetch 获取图片数据
const response = await fetch(imageUrl);
const blob = await response.blob(); // 将响应转为 Blob
// 创建一个 URL 对象
const url = window.URL.createObjectURL(blob);
// 创建一个 <a> 标签并设置其下载属性
const a = document.createElement('a');
a.href = url;
a.download = fileName; // 指定下载的文件名
a.click(); // 触发下载
// 释放对象 URL
window.URL.revokeObjectURL(url);
} catch (error) {
console.error('下载图片失败:', error);
}
}

View File

@ -45,7 +45,7 @@ service.interceptors.request.use(config => {
const requestSize = Object.keys(JSON.stringify(requestObj)).length; // 请求数据大小
const limitSize = 5 * 1024 * 1024; // 限制存放数据5M
if (requestSize >= limitSize) {
console.warn(`[${config.url}]: ` + '请求数据大小超出允许的5M限制无法进行防重复提交验证。')
console.warn(`[${config.url}]: ` + '请求数据大小超出允许的5M限制, 无法进行防重复提交验证。')
return config;
}
const sessionObj = cache.session.getJSON('sessionObj')
@ -55,7 +55,8 @@ service.interceptors.request.use(config => {
const s_url = sessionObj.url; // 请求地址
const s_data = sessionObj.data; // 请求数据
const s_time = sessionObj.time; // 请求时间
const interval = 1000; // 间隔时间(ms),小于此时间视为重复提交
const interval = 0; // 间隔时间(ms),小于此时间视为重复提交
// const interval = 1000; // 间隔时间(ms),小于此时间视为重复提交
if (s_data === requestObj.data && requestObj.time - s_time < interval && s_url === requestObj.url) {
const message = '数据正在处理,请勿重复提交';
console.warn(`[${s_url}]: ` + message)
@ -82,18 +83,22 @@ service.interceptors.response.use(res => {
return res.data
}
if (code === 401) {
if (!isRelogin.show) {
isRelogin.show = true;
MessageBox.confirm('登录状态已过期,您可以继续留在该页面,或者重新登录', '系统提示', { confirmButtonText: '重新登录', cancelButtonText: '取消', type: 'warning' }).then(() => {
isRelogin.show = false;
store.dispatch('LogOut').then(() => {
location.href = '/index';
})
}).catch(() => {
isRelogin.show = false;
});
}
return Promise.reject('无效的会话,或者会话已过期,请重新登录。')
store.dispatch('LogOut').then(() => {
// location.href = '/index';
})
// this.$eventBus.$emit("showLogin");
// if (!isRelogin.show) {
// isRelogin.show = true;
// MessageBox.confirm('登录状态已过期,您可以继续留在该页面,或者重新登录', '系统提示', { confirmButtonText: '重新登录', cancelButtonText: '取消', type: 'warning' }).then(() => {
// isRelogin.show = false;
// store.dispatch('LogOut').then(() => {
// location.href = '/index';
// })
// }).catch(() => {
// isRelogin.show = false;
// });
// }
// return Promise.reject('无效的会话,或者会话已过期,请重新登录。')
} else if (code === 500) {
Message({ message: msg, type: 'error' })
return Promise.reject(new Error(msg))

View File

@ -0,0 +1,32 @@
import { mallProductFile } from "@/api/mcwl/utils";
/**
* 分批次上传图片
* @param {File[]} files - 需要上传的图片文件数组
* @param {string} url - 上传接口的 URL
* @param {number} batchSize - 每批次上传的文件数量默认为 3
* @returns {Promise<{ success: boolean, message: string, data: any[] }>} - 返回上传结果
*/
export const uploadImagesInBatches = async (files, batchSize = 3) => {
const uploadResults = [];
for (let i = 0; i < files.length; i++) {
const file = files[i];
// 创建 FormData 对象
const formData = new FormData();
formData.append('file', file); // 假设后端接收字段是 `file`
// 上传当前图片
try {
console.log('object', formData);
const res = await mallProductFile(formData)
uploadResults.push(res.msg);
} catch (error) {
console.error(`图片上传失败: ${file.name}`, error);
uploadResults.push({ success: false, error });
}
}
return uploadResults;
}

View File

@ -0,0 +1,439 @@
<template>
<div class="container">
<div class="banner-content"></div>
<div class="info-content">
<div class="edit-info-content">
<div class="mc-head">
<div class="mc-head-inner">
<img class="head-img" :src="avatar" alt="" />
</div>
</div>
<div class="edit-info" @click="onEditInfo(true)"></div>
<div v-if="idName" class="edit-info"></div>
<div v-else class="edit-info" @click="onShowId(true)"></div>
</div>
<div class="user-info">
<div class="nickname">
{{ nickName }}
</div>
<div class="info-desc">
{{ userInfo.brief }}
</div>
<div class="production-state">
<div class="production-state-item">
<span class="production-state-number">{{ selectUserInfo.bean }}</span
>粉丝
</div>
<div class="production-state-item">
<span class="production-state-number">{{ selectUserInfo.attention }}</span
>关注
</div>
<div class="production-state-item">
<span class="production-state-number">{{ selectUserInfo.download }}</span
>作品被使用次数
</div>
<div class="production-state-item">
<span class="production-state-number">{{ selectUserInfo.likeCount }}</span
>作品被点赞次数
</div>
</div>
</div>
</div>
<div class="mc-tabs">
<div
class="mc-tabs-btn"
v-for="(item, index) in stateList"
:key="index"
:style="{
background: currentState === item.id ? '#000' : '#fff',
color: currentState === item.id ? '#fff' : '#000',
}"
@click="changeTabs(item.id)"
>
{{ item.title }}
</div>
</div>
<div class="select-content">
<div class="mc-felx select-type">
<div
v-for="(item, index) in typeList"
@click="changeType(item.id)"
:key="index"
class="select-type-item"
:style="{ background: item.id === publishParams.type ? '#fff' : '#f4f5f9' }"
>
{{ item.title }}
</div>
<!-- <div class="select-type-item">工作流</div>
<div class="select-type-item">图片</div> -->
</div>
<!-- 发布的form -->
<div class="mc-felx" v-if="currentState === 'mallProduct'">
<div class="custom-select">
<!-- // -->
<el-select size="small" v-model="publishParams.status" placeholder="请选择">
<el-option
v-for="item in statusOptions"
:key="item.dictValue"
@change="changeStatus"
:label="item.dictLabel"
:value="item.dictValue"
>
</el-option>
</el-select>
</div>
<!-- 最新/热度 -->
<div class="custom-select">
<el-select size="small" v-model="publishParams.order" placeholder="请选择">
<el-option
v-for="item in orderOptions"
:key="item.dictValue"
@change="changeOrder"
:label="item.dictLabel"
:value="item.dictValue"
>
</el-option>
</el-select>
</div>
<!-- // -->
<div class="custom-select">
<el-date-picker
size="small"
@change="changeDate"
v-model="publishParams.date"
type="daterange"
value-format="yyyy-MM-dd"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
>
</el-date-picker>
</div>
</div>
<!-- //form -->
<div class="mc-felx" v-if="currentState === 'like'">
<!-- 最新/热度 -->
<div class="custom-select">
<el-select size="small" v-model="likesParams.order" placeholder="请选择">
<el-option
v-for="item in orderOptions"
:key="item.dictValue"
@change="changeLikeOrder"
:label="item.dictLabel"
:value="item.dictValue"
>
</el-option>
</el-select>
</div>
</div>
</div>
<div class="edit-info-dialog" v-if="isShowEditInfo">
<McEditInfo :userInfo="userInfo" @closeEditInfo="onEditInfo"></McEditInfo>
</div>
<div class="login-content">
<LikeWorks v-show="currentState === 'like'" :order="likesParams.order"></LikeWorks>
<PublishedWorks
v-show="currentState === 'mallProduct'"
:status="publishParams.status"
:order="publishParams.order"
:date="publishParams.date"
></PublishedWorks>
</div>
<NameAuth v-if="isShowId" @closeNameAuth="onCloseNameAuth"></NameAuth>
</div>
</template>
<script>
import { getSelectUserInfo, dictType, userInfo } from "@/api/mcwl/personalCenter";
import McEditInfo from "@/components/McEditInfo";
import McLogin from "@/components/McLogin";
import { mapGetters } from "vuex";
import PublishedWorks from "@/components/PublishedWorks";
import LikeWorks from "@/components/LikeWorks";
import NameAuth from "@/components/NameAuth";
export default {
name: "McPersonalCenter",
data() {
return {
isShowId: false,
selectUserInfo: {},
// currentSelect:'mallProduct', //MallProductf like
orderOptions: [],
statusOptions: [],
userInfo: {},
isShowEditInfo: false,
currentState: "mallProduct",
stateList: [
{
id: "mallProduct",
title: "发布",
},
{
id: "like",
title: "点赞",
},
],
typeList: [
{
id: "0",
title: "模型",
},
{
id: "1",
title: "工作流",
},
{
id: "2",
title: "图片",
},
],
likesParams: {
order: "0", // 1
},
publishParams: {
type: "0", //(0 1 2 3)
status: "0", //(0 1 2 3 4)
order: "0", // 1
startTime: "", // yyyy-MM-dd HH:mm:ss
endTime: "", // yyyy-MM-dd HH:mm:ss
date: [],
},
};
},
components: {
McEditInfo,
McLogin,
PublishedWorks,
LikeWorks,
NameAuth,
},
computed: {
...mapGetters(["user", "nickName", "avatar", "idName"]),
},
methods: {
changeType(id) {
this.publishParams.type = id;
},
onCloseNameAuth() {
this.isShowId = false;
},
onShowId() {
this.isShowId = true;
},
changeDate(data) {
if (!data) {
this.publishParams.date = [];
console.log("11", this.publishParams.date);
} else {
this.publishParams.date = data;
console.log("22", this.publishParams.date);
}
},
changeStatus(ag) {
this.publishParams.status = ag;
},
changeOrder(ag) {
this.publishParams.order = ag;
},
changeLikeOrder(id) {
this.likesParams.order = id;
},
// /
changeTabs(id) {
this.currentState = id;
console.log("currentState", this.currentState);
},
onEditInfo(ag) {
this.isShowEditInfo = ag;
},
//
onGetSelectUserInfo() {
getSelectUserInfo()
.then((res) => {
this.selectUserInfo = res.data;
})
.catch((err) => {
console.log("err-----", err);
});
},
// //
async getDictType() {
try {
const res = await dictType({ type: "mall_product_status" });
const res2 = await dictType({ type: "mall_product_order" });
this.orderOptions = res2.data;
this.statusOptions = res.data;
// this.publishParams.status = res.data[0].dictValue
// this.publishParams.order = res2.data[0].dictValue
} catch (error) {
console.log(error);
}
},
// //
getUserInfo() {
userInfo({}).then((res) => {
this.userInfo = res.data;
});
},
},
mounted() {
this.getDictType();
this.onGetSelectUserInfo();
// this.getUserInfo()
},
};
</script>
<style scoped lang="scss">
.header-btn {
color: #1890ff;
}
.edit-info-dialog {
background-color: rgba($color: #000000, $alpha: 0.5);
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
}
.mc-felx {
display: flex;
align-items: center;
.custom-select {
margin-right: 10px;
}
.el-select {
width: 120px;
}
}
.container {
.banner-content {
width: 100%;
height: 120px;
// background-image: url(../../assets//images/bg.png);
background-image: url(https://liblibai-web-static.liblib.cloud/liblibai_v4_online/static/_next/static/images/defaultBgImg.381282c0f2b01780c83d8fe6dc0aa90a.png);
background-repeat: no-repeat;
background-size: 100% 150px;
display: flex;
align-items: center;
justify-content: flex-end;
padding-right: 40px;
> img {
width: 100px;
height: 50px;
}
}
.info-content {
display: flex;
flex-direction: column;
justify-content: center;
padding: 20px;
margin-top: -50px;
.edit-info-content {
display: flex;
align-items: center;
.mc-head {
border-radius: 50px;
width: 80px;
height: 80px;
margin-right: 20px;
background-color: #fff;
margin-right: 20px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.2);
.mc-head-inner {
background-color: #a6d4ff;
margin: 3px;
width: 74px;
height: 74px;
border-radius: 50%;
.head-img {
background-color: #fff;
margin: 2px;
width: 70px;
height: 70px;
border-radius: 50%;
}
}
}
.edit-info {
margin-right: 10px;
cursor: pointer;
padding: 4px 20px;
line-height: 30px;
background-color: #fff;
border-radius: 20px;
box-shadow: 0 2px 10px 0 rgba(0, 0, 0, 0.2);
font-size: 14px;
}
}
.user-info {
margin-top: 10px;
.nickname {
font-size: 24px;
font-weight: 600;
}
.info-desc {
margin: 4px 0 10px 0;
color: #2c2b2b;
font-size: 14px;
}
.production-state {
display: flex;
color: #2c2b2b;
font-size: 14px;
.production-state-item {
margin-right: 20px;
.production-state-number {
color: #000000;
font-weight: 600;
margin-right: 4px;
}
}
}
}
}
.mc-tabs {
border-bottom: 1px solid #dcdcdc;
padding: 0 20px;
display: flex;
.mc-tabs-btn {
margin-bottom: 10px;
padding: 4px 20px;
border-radius: 20px;
margin-right: 10px;
color: #272727;
text-align: center;
line-height: 20px;
cursor: pointer;
}
}
.select-content {
margin-top: 10px;
align-items: center;
font-size: 14px;
padding: 0 20px;
display: flex;
justify-content: space-between;
.select-type {
background-color: #f4f5f9;
border-radius: 20px;
.select-type-item {
margin: 4px;
border-radius: 20px;
padding: 4px 18px;
font-size: 12px;
cursor: pointer;
}
}
}
}
</style>

View File

@ -0,0 +1,168 @@
<template>
<div class="container">
<div class="search-container">
<!-- 输入框 -->
<input
type="text"
v-model="searchText"
placeholder="搜索模型/图片/作者寻找灵感"
/>
<!-- 按钮 -->
<button @click="performSearch"></button>
</div>
<div class="select-content">
<div class="mc-felx select-type">
</div>
<!-- 发布的form -->
<div class="mc-felx">
<div class="custom-select">
<!-- // -->
<el-select size="small" v-model="publishParams.status" placeholder="请选择">
<el-option
v-for="item in statusOptions"
:key="item.dictValue"
@change="changeStatus"
:label="item.dictLabel"
:value="item.dictValue">
</el-option>
</el-select>
</div>
<!-- 最新/热度 -->
<div class="custom-select">
<el-select size="small" v-model="publishParams.order" placeholder="请选择">
<el-option
v-for="item in orderOptions"
:key="item.dictValue"
@change="changeOrder"
:label="item.dictLabel"
:value="item.dictValue">
</el-option>
</el-select>
</div>
<!-- // -->
<div class="custom-select">
<el-date-picker
size="small"
@change="changeDate"
v-model="publishParams.date"
type="daterange"
value-format="yyyy-MM-dd"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期">
</el-date-picker>
</div>
</div>
</div>
</div>
</template>
<script>
import { getMallProductList } from "@/api/mcwl/mallProduct";
export default {
data() {
return {
publishParams:{},
statusOptions:[],
orderOptions:[],
searchText: "",
}
},
methods: {
changeDate(){},
changeOrder(){},
changeStatus(){},
performSearch() {
if (this.searchText.trim() === "") {
alert("请输入搜索内容!");
return;
}
alert(`搜索内容为:${this.searchText}`);
},
},
}
</script>
<style lang="scss" scoped>
// _variables.scss
$primary-color: #007bff;
$text-color: #6c757d;
$placeholder-color: #adb5bd;
$icon-color: #adb5bd;
.container{
padding: 20px;
.search-container {
display: flex;
align-items: center;
border: 2px solid $primary-color;
border-radius: 25px;
padding: 5px 10px;
background-color: #fff;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
width: 400px;
input {
border: none;
outline: none;
font-size: 16px;
padding: 8px;
flex: 1;
border-radius: 20px;
color: $text-color;
background-color: transparent;
&::placeholder {
color: $placeholder-color;
}
}
.icon {
margin-right: 10px;
color: $icon-color;
cursor: pointer;
}
button {
background-color: $primary-color;
color: white;
border: none;
border-radius: 20px;
padding: 8px 16px;
font-size: 16px;
cursor: pointer;
transition: background-color 0.2s;
&:hover {
background-color: darken($primary-color, 10%);
}
}
}
.select-content{
margin-top: 10px;
align-items: center;
font-size: 14px;
padding: 0 20px;
display: flex;
justify-content: space-between;
.select-type{
background-color: #f1f1f1;
border-radius: 20px;
.select-type-item{
padding: 4px 18px;
cursor: pointer;
}
}
.mc-felx{
display: flex;
align-items: center;
.custom-select{
margin-right: 10px;
}
.el-select{
width: 120px;
}
}
}
}
</style>

View File

@ -0,0 +1,219 @@
<template>
<div class="create-model">
<!-- 步骤条 -->
<div class="steps">
<div class="step">
<el-steps :active="currentStep" align-center>
<el-step title="创建模型"></el-step>
<el-step title="编辑版本"></el-step>
<el-step title="上传图片"></el-step>
</el-steps>
</div>
</div>
<input
type="file"
@change="handlePictureChange"
accept="image/*"
ref="pictureInput"
style="display: none"
/>
<!-- 表单区域 1-->
<div class="form-content" v-show="currentStep === 1">
<CreateModel
@stepNext="stepNext"
@changeCreateModelInfo="changeCreateModelInfo"
></CreateModel>
</div>
<!-- 表单区域 2-->
<div class="form-content" v-show="currentStep === 2">
<EditVersion
@stepNext="stepNext"
@changeEditVersionInfo="changeEditVersionInfo"
></EditVersion>
</div>
<div class="form-content" v-show="currentStep === 3">
<div class="uploadImg">
<div class="version-item" v-for="(item, index) in editVersionInfo" :key="index">
<div>版本名字: {{ item.name }}</div>
<div class="version-desc">
添加版本实例图片 <span class="required-icon">*</span>
</div>
<div class="upload-img-container">
<div class="upload-img-btn" @click="onUploadImg(index)"></div>
<!-- <div
style="
font-size: 14px;
margin-top: 10px;
font-weight: 600;
color: rgb(94 94 94);
"
>
建议从图库上传便于用户画不同款来适用模型效果
</div> -->
<div class="upload-img-tips">
支持格式.safetensors/.ckpt/.pt/.bin/.path/.gguf/.sft
</div>
</div>
</div>
<div class="step-group">
<div class="step1-group">
<div
class="step-btn step1"
style="background-color: #f1f2f7; color: #000;"
@click="stepNext(2)"
>
上一步
</div>
<div class="step-btn step1" @click="onPublish(3)"></div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import { uploadImagesInBatches } from "@/utils/uploadImages.js";
// import RichTextEditor from "@/components/WangEditor";
import CreateModel from "@/components/CreateModels";
import EditVersion from "@/components/EditVersion";
export default {
data() {
return {
editVersionInfo: [{ name: "1.1" }, { name: "1.2" }],
currentStep: 3,
CreateModelInfo: {},
//
};
},
components: {
// RichTextEditor,
CreateModel,
EditVersion,
currentUploadImg: null,
},
methods: {
//
async handlePictureChange(event) {
console.log("object", event);
const files = event.target.files;
if (files.length > 1) {
alert("只能选择 1 张图片");
return;
}
let imageFiles = [];
for (let i = 0; i < files.length; i++) {
const file = files[i];
if (file.type.startsWith("image/")) {
imageFiles.push(file);
// this.imageUrls.push(URL.createObjectURL(file)); // URL
} else {
alert("请选择有效的图片文件");
}
}
const pictureResultList = await uploadImagesInBatches(imageFiles);
this.ruleForm.avatar = pictureResultList[0];
},
//
onUploadImg(index) {
this.$refs.pictureInput.click();
this.currentUploadImg = index;
},
//
changeCreateModelInfo(info) {
this.CreateModelInfo = info;
},
stepNext(index) {
this.currentStep = index;
},
//
changeEditVersionInfo(info) {
// this.editVersionInfo = info;
},
//
onPublish() {},
},
created() {
// this.getDictType();
},
};
</script>
<style lang="scss" scoped>
.create-model {
padding: 20px 0;
.form-content {
margin: 10px 80px;
padding: 20px 10px;
border-radius: 8px;
font-size: 14px;
.uploadImg {
font-size: 16px;
padding: 20px;
.version-item {
background-color: #f4f5f9;
padding: 20px;
margin: 20px 0;
border-radius: 10px;
.version-desc {
font-size: 14px;
margin-top: 10px;
}
.required-icon {
color: red;
}
.upload-img-container {
margin-top: 10px;
width: 100%;
height: 150px;
border: 1px dashed #ccc;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
background-color: #fff;
border-radius: 10px;
.upload-img-btn {
padding: 4px 20px;
text-align: center;
background-color: rgb(45, 40, 255);
color: #fff;
border-radius: 4px;
cursor: pointer;
}
.upload-img-tips {
font-size: 12px;
color: #999;
margin-top: 10px;
}
}
}
.step-group {
display: flex;
align-items: center;
justify-content: center;
.step-btn {
width: 200px;
height: 40px;
margin-right: 20px;
text-align: center;
line-height: 40px;
}
.step1-group {
display: flex;
background-color: blue;
border-radius: 4px;
color: #fff;
cursor: pointer;
}
}
}
}
}
</style>

View File

@ -0,0 +1,177 @@
<template>
<div class="container">
<div class="header">
<div class="user-info">
<div class="user-name">用户名</div>
<div class="model-info">
<div>下载0</div>
<div>不可下载</div>
<div>图片0</div>
<div>心0</div>
</div>
</div>
<div class="tags-group">
<div class="tags">标签1</div>
<div class="tags">标签2</div>
<div class="tags">标签3</div>
</div>
</div>
<div class="content">
<div class="content-left">
<el-tabs v-model="activeName" @tab-click="handleClick">
<el-tab-pane v-for="(item, index) in contentList" :key="index" :label="item.title" :name="item.id">
<!-- {{ item.title }} -->
<div class="reprint-originator">
转载自作者魔创未来
</div>
<div class="versions-info">
<div class="versions-title">
版本介绍
</div>
<div class="versions-img">
<img src="">
</div>
</div>
</el-tab-pane>
</el-tabs>
</div>
<div class="content-right">
<div class="content-right-user-info">
<div class="user-avatar">
</div>
<div class="model-info">
<div class="user-name">用户名</div>
<div class="user-tags">
<div>下载0</div>
<div>不可下载</div>
<div>图片0</div>
<div>心0</div>
</div>
</div>
</div>
<div class="btn-group">
<div>
立即生图
</div>
<div>
<div>加入模型库</div>
<div>不可下载</div>
</div>
<div>
已验证 2026/01/01
</div>
</div>
<div class="right-version-info">
<div class="version-info-title">版本详情</div>
<div class="">
<div>类型</div>
<div>ESFPSPFDF</div>
</div>
<div class="">
<div>在线生成数</div>
<div>暂无</div>
</div>
<div class="">
<div>下载量</div>
<div>作者设置不可下载</div>
</div>
<div class="">
<div>基础算法</div>
<div>基础模型F1</div>
</div>
<div class="">
<div>触发词</div>
<div>触发词2</div>
</div>
</div>
<div class="right-version-info">
<div class="version-info-title">推荐参数</div>
<div class="">
<div>采样方法</div>
<div>EULER, DOOPP</div>
</div>
<div class="">
<div>CFG</div>
<div>3.5</div>
</div>
<div class="">
<div>VAE</div>
<div></div>
</div>
<div class="">
<div>高清放大算法</div>
<div>LASDF</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
data(){
return {
currentVersion: {
id:'1',
title: '用户管理',
version: '1.0.0',
xiazailiang: '0',
bukexiazai: '0',
tupian: '0',
xin: '0'
},
contentList: [
{
id:'1',
title: '用户管理',
version: '1.0.0',
xiazailiang: '0',
bukexiazai: '0',
tupian: '0',
xin: '0'
},
{
id:'2',
title: '配置管理',
id:'1',
title: '用户管理',
version: '1.0.0',
xiazailiang: '0',
bukexiazai: '0',
tupian: '0',
xin: '0'
}
],
activeName: '1'
}
},
methods: {
handleClick(tab, event) {
console.log(tab, event);
}
}
}
</script>
<style lang="scss" scoped>
.container{
.header{
.user-info{
display: flex;
.user-name{
font-size: 20px;
}
.model-info{
display: flex;
}
}
.tags-group{
display: flex;
.tags{
margin-right: 10px;
}
}
}
}
</style>

View File

@ -156,7 +156,7 @@
</el-col>
<el-col :span="24">
<el-form-item label="内容">
<editor v-model="form.noticeContent" :min-height="192"/>
<!-- <editor v-model="form.noticeContent" :min-height="192"/> -->
</el-form-item>
</el-col>
</el-row>

View File

@ -0,0 +1,414 @@
<template>
<div class="membership-page bg-[#1C1C1C]">
<!-- 左侧用户信息卡片 -->
<div class="user-info-card">
<div class="user-card">
<div class="user-profile">
<div class="avatar">
<img src="default-avatar.png" alt="头像" />
</div>
<div class="user-id">微信用户a98592</div>
<div class="member-status">
<span class="diamond-icon"></span>
您还不是魔创未来会员
</div>
<button class="activate-btn" @click="openMembership(0)"></button>
<div class="free-trial">兑换会员</div>
</div>
</div>
<div class="vip-privileges">
<!-- 顶部余额信息 -->
<div class="balance-info">
<div class="balance-item">
<div class="title">算力余额</div>
<div class="value">
300
<span class="recharge">充值 ></span>
</div>
<div class="sub-text">算力明细 ></div>
</div>
<div class="balance-item">
<div class="title">生图加速余额</div>
<div class="value">
0
<span class="recharge">充值 ></span>
</div>
<div class="sub-text">加速明细 ></div>
</div>
<div class="balance-item">
<div class="title">训练加速余额</div>
<div class="value">0</div>
</div>
</div>
<!-- 空间使用信息 -->
<div class="storage-info">
<div class="tabs">
<div class="tab">我的存储空间</div>
<div class="tab">管理图库</div>
<div class="tab">管理训练</div>
</div>
<div class="usage">
<span class="blue-dot"></span>生图 <span class="green-dot"></span>训练
<span class="space-usage">0G/3G</span>
</div>
<div class="usage-bar"></div>
</div>
</div>
</div>
<!-- 右侧内容区域 -->
<div class="main-content">
<!-- 会员类型选项卡 -->
<!-- <div class="membership-tabs">
<div class="tab active">LiblibAI-会员</div>
<div class="tab">
LiblibAI-训练会员
<span class="trial-tag">可与LiblibAI会员叠加</span>
</div>
</div> -->
<!-- 会员套餐卡片 -->
<div class="plans-container">
<div class="plan-card" v-for="(plan, index) in plans" :key="index">
<div class="discount-tag" v-if="plan.discount">{{ plan.discount }}</div>
<div class="plan-header">
<span class="plan-icon">{{ plan.icon }}</span>
<span class="plan-name">{{ plan.name }}</span>
</div>
<div class="price">
<span class="currency">¥</span>
<span class="amount">{{ plan.price }}</span>
<span class="original-price">¥{{ plan.originalPrice }}</span>
</div>
<div class="price-detail">{{ plan.detail }}</div>
<div class="subscribe-btn" @click="openMembership(plan.price)"></div>
</div>
</div>
<div>
<vipRights></vipRights>
</div>
</div>
<vipPay v-if="isPay" @closeVipPay="closeVipPay"></vipPay>
</div>
</template>
<script>
import vipRights from '@/components/vipRights'
import vipPay from '@/components/vipPay'
export default {
data() {
return {
isPay:true,
plans: [
{
discount: 264,
icon: "🏆",
name: "基础版VIP连续包月",
price: 39,
originalPrice: 50,
detail: "低至¥28.00元/月",
},
{
icon: "🏆",
name: "基础版VIP 12个月",
price: 336,
originalPrice: 600,
detail: "低至¥28.00元/月",
},
{
icon: "🏆",
name: "基础版VIP 12个月",
price: 336,
originalPrice: 600,
detail: "到期按¥70/月续费可随时取消",
},
// ...
],
};
},
methods: {
openMembership(){
this.isPay = true
},
closeVipPay(){
this.isPay = false
}
},
components: {
vipRights,
vipPay
}
};
</script>
<style lang="scss" scoped>
.membership-page {
// display: flex;
min-height: 100vh;
padding: 20px;
color: #fff;
}
.user-info-card {
background-color: #1e1915; //
display: flex;
.user-card {
width: 300px;
background: rgba(40, 35, 30, 0.95); //
border-radius: 12px;
padding: 20px;
margin-right: 20px;
height: fit-content;
.user-profile {
text-align: center;
.avatar {
width: 80px;
height: 80px;
border-radius: 50%;
margin: 0 auto 12px;
overflow: hidden;
img {
width: 100%;
height: 100%;
object-fit: cover;
}
}
.user-id {
font-size: 16px;
margin-bottom: 8px;
}
.member-status {
color: #999;
font-size: 14px;
.diamond-icon {
color: #ccc;
margin-right: 4px;
}
}
}
.activate-btn {
cursor: pointer;
width: 100%;
background: #ffe7ba;
color: #8b4513;
padding: 12px;
border-radius: 24px;
margin: 20px 0 12px;
font-weight: bold;
}
.free-trial {
text-align: center;
color: #999;
font-size: 14px;
cursor: pointer;
}
}
.vip-privileges{
.balance-info {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 20px;
margin-bottom: 20px;
.balance-item {
background: rgba(40, 35, 30, 0.95); //
border-radius: 12px;
padding: 20px;
.title {
color: #999;
margin-bottom: 8px;
}
.value {
font-size: 18px;
margin-bottom: 8px;
.recharge {
color: #999;
font-size: 14px;
margin-left: 8px;
}
}
.sub-text {
color: #999;
font-size: 14px;
}
}
}
.storage-info {
background: rgba(40, 35, 30, 0.95);
border-radius: 12px;
padding: 20px;
margin-bottom: 20px;
.tabs {
display: flex;
gap: 20px;
margin-bottom: 12px;
.tab {
color: #999;
cursor: pointer;
}
}
.usage {
display: flex;
align-items: center;
gap: 12px;
margin-bottom: 8px;
.blue-dot,
.green-dot {
width: 8px;
height: 8px;
border-radius: 50%;
}
.blue-dot {
background: #007aff;
}
.green-dot {
background: #34c759;
}
.space-usage {
margin-left: auto;
}
}
.usage-bar {
height: 4px;
background: #3a3a3a;
border-radius: 2px;
}
}
}
}
.main-content {
background: #fff5e2;
padding-top: 20px;
.membership-tabs {
display: flex;
gap: 20px;
margin-bottom: 20px;
.tab {
padding: 12px 24px;
cursor: pointer;
position: relative;
&.active {
color: #f5a623;
border-bottom: 2px solid #f5a623;
}
.trial-tag {
position: absolute;
top: -8px;
right: -8px;
background: #f5a623;
color: #fff;
font-size: 12px;
padding: 2px 8px;
border-radius: 12px;
}
}
}
.plans-container {
display: flex;
gap: 20px;
// overflow-x: auto;
padding-bottom: 20px;
.plan-card {
min-width: 280px;
background: #ffefd9;
border-radius: 12px;
padding: 20px;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
position: relative;
border: 1px solid #ffffff;
.discount-tag {
position: absolute;
top: -12px;
left: 0px;
background: #ff3b30;
color: #fff;
font-size: 12px;
padding: 2px 8px;
border-radius: 12px;
}
.plan-header {
display: flex;
align-items: center;
gap: 8px;
margin-bottom: 16px;
.plan-name{
color: #e08909;
}
}
.price {
margin-bottom: 12px;
.currency {
font-size: 20px;
color: #814600;
margin-right: 6px;
}
.amount {
font-size: 24px;
font-weight: bold;
color: #814600;
}
.original-price {
color: #999;
text-decoration: line-through;
margin-left: 8px;
}
}
.price-detail {
color: #d27f08;
font-size: 14px;
margin-bottom: 16px;
}
.subscribe-btn {
text-align: center;
width: 100%;
background: #ffe7ba;
color: #8b4513;
padding: 12px;
border-radius: 24px;
font-weight: bold;
font-size: 14px;
cursor: pointer;
}
}
}
}
</style>

View File

@ -0,0 +1,163 @@
<template>
<div class="container">
<div class="steps">
<div class="step">
<el-steps :active="currentStep" align-center>
<el-step title="编辑工作流"></el-step>
<el-step title="编辑版本"></el-step>
<el-step title="上传图片"></el-step>
</el-steps>
</div>
</div>
<div class="edit-workflow" v-show="currentStep===1">
<EditWorkFlow @changeWorkFlowInfo="changeWorkFlowInfo" @nextStep="onNextStep"></EditWorkFlow>
</div>
<div class="edit-workflow" v-show="currentStep===2">
<EditWorkFlowVersion @changeEditVersionWorkFlowInfo="changeEditVersionWorkFlowInfo" @stepNext="onNextStep"></EditWorkFlowVersion>
</div>
<div class="form-content" v-show="currentStep === 3">
<div class="uploadImg">
<div class="version-item" v-for="(item, index) in editVersionInfo" :key="index">
<div>版本名字: {{ item.name }}</div>
<div class="version-desc">
添加版本实例图片 <span class="required-icon">*</span>
</div>
<div class="upload-img-container">
<div class="upload-img-btn" @click="onUploadImg(index)"></div>
<!-- <div
style="
font-size: 14px;
margin-top: 10px;
font-weight: 600;
color: rgb(94 94 94);
"
>
建议从图库上传便于用户画不同款来适用模型效果
</div> -->
<div class="upload-img-tips">
支持格式.safetensors/.ckpt/.pt/.bin/.path/.gguf/.sft
</div>
</div>
</div>
<div class="step-group">
<div class="step1-group">
<div
class="step-btn step1"
style="background-color: #f1f2f7; color: #000;"
@click="onNextStep(2)"
>
上一步
</div>
<div class="step-btn step1" @click="onPublish()"></div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import EditWorkFlow from "@/components/editWorkFlow";
import EditWorkFlowVersion from "@/components/editWorkFlowVersion";
export default {
data() {
return {
currentStep: 2,
editWorkFlowInfo: {},
editVersionWorkFlowInfo:{},
editVersionInfo: [{ name: "1.1" }, { name: "1.2" }],
};
},
components: {
EditWorkFlow,
EditWorkFlowVersion
},
methods: {
changeEditVersionWorkFlowInfo(info){
this.editVersionWorkFlowInfo = info;
},
changeWorkFlowInfo(info) {
this.editWorkFlowInfo = info;
},
onNextStep(index) {
this.currentStep = index;
},
onPublish(){}
},
};
</script>
<style lang="scss" scoped>
.container {
padding: 20px;
.edit-workflow{
margin: 0 80px
}
.form-content {
margin: 10px 80px;
padding: 20px 10px;
border-radius: 8px;
font-size: 14px;
.uploadImg {
font-size: 16px;
.version-item {
background-color: #f4f5f9;
padding: 20px;
margin: 20px 0;
border-radius: 10px;
.version-desc {
font-size: 14px;
margin-top: 10px;
}
.required-icon {
color: red;
}
.upload-img-container {
margin-top: 10px;
width: 100%;
height: 150px;
border: 1px dashed #ccc;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
background-color: #fff;
border-radius: 10px;
.upload-img-btn {
padding: 4px 20px;
text-align: center;
background-color: rgb(45, 40, 255);
color: #fff;
border-radius: 4px;
cursor: pointer;
}
.upload-img-tips {
font-size: 12px;
color: #999;
margin-top: 10px;
}
}
}
.step-group {
display: flex;
align-items: center;
justify-content: center;
.step-btn {
width: 200px;
height: 40px;
margin-right: 20px;
text-align: center;
line-height: 40px;
}
.step1-group {
display: flex;
background-color: blue;
border-radius: 4px;
color: #fff;
cursor: pointer;
}
}
}
}
}
</style>

View File

@ -36,7 +36,10 @@ module.exports = {
proxy: {
// detail: https://cli.vuejs.org/config/#devserver-proxy
[process.env.VUE_APP_BASE_API]: {
target: `http://1.13.246.108:8080`,
// target: `https://702bc39c.r27.cpolar.top`,
// 192.168.1.69 海洋
//192.168.2.22 代
target: `http://192.168.2.22:8080`,
changeOrigin: true,
pathRewrite: {
['^' + process.env.VUE_APP_BASE_API]: ''
@ -59,6 +62,15 @@ module.exports = {
'@': resolve('src')
}
},
module: {
rules: [
{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules\/(?!quill)/, // 排除 node_modules但包含 quill
},
],
},
plugins: [
// http://doc.ruoyi.vip/ruoyi-vue/other/faq.html#使用gzip解压缩静态文件
new CompressionPlugin({