Compare commits

...

No commits in common. 'main' and 'main1' have entirely different histories.
main ... main1

@ -0,0 +1,3 @@
> 1%
last 2 versions
not dead

@ -0,0 +1 @@
VUE_APP_SERVER_URL = 'http://127.0.0.1:8000'

23
.gitignore vendored

@ -0,0 +1,23 @@
.DS_Store
node_modules
/dist
# local env files
.env.local
.env.*.local
# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

@ -1,2 +0,0 @@
# child_star

@ -0,0 +1,5 @@
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset'
]
}

26639
package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -0,0 +1,34 @@
{
"name": "doubao_community_frontend",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build"
},
"dependencies": {
"axios": "^0.21.1",
"buefy": "^0.9.4",
"core-js": "^3.6.5",
"darkreader": "^4.9.27",
"date-fns": "^2.17.0",
"dayjs": "^1.10.4",
"element-ui": "^2.15.14",
"js-cookie": "^2.2.1",
"nprogress": "^0.2.0",
"vditor": "^3.8.1",
"vue": "^2.6.11",
"vue-lazyload": "^3.0.0",
"vue-router": "^3.2.0",
"vuedraggable": "^2.24.3",
"vuex": "^3.4.0"
},
"devDependencies": {
"@vue/cli-plugin-babel": "~4.5.0",
"@vue/cli-plugin-router": "~4.5.0",
"@vue/cli-plugin-vuex": "~4.5.0",
"@vue/cli-service": "~4.5.0",
"@vue/compiler-sfc": "^3.3.10",
"vue-template-compiler": "^2.6.11"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

@ -0,0 +1,17 @@
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>

@ -0,0 +1,33 @@
<template>
<div>
<div class="mb-5">
<Header></Header>
</div>
<div class="container context">
<router-view :key="this.$route.fullPath"></router-view>
</div>
<div>
<Footer></Footer>
</div>
</div>
</template>
<script>
import Header from "@/components/Layout/Header";
import Footer from "@/components/Layout/Footer";
export default {
name: "App",
components: { Header, Footer },
};
</script>
<style scoped>
.container {
min-height: 500px;
}
</style>

@ -0,0 +1,32 @@
import request from '@/utils/request'
// 注册
export function userRegister(userDTO) {
return request({
url: '/ums/user/register',
method: 'post',
data: userDTO
})
}
// 前台用户登录
export function login(data) {
return request({
url: '/ums/user/login',
method: 'post',
data
})
}
// 登录后获取前台用户信息
export function getUserInfo() {
return request({
url: '/ums/user/info',
method: 'get'
})
}
// 前台用户注销
export function logout() {
return request({
url: '/ums/user/logout'
})
}

@ -0,0 +1,9 @@
import request from '@/utils/request'
//获得一级分类
export function getBillboard() {
return request({
url: '/billboard/show',
method: 'get'
})
}

@ -0,0 +1,19 @@
import request from '@/utils/request'
//品牌获取申请需求的模特详情
export function getApplyModel(){
return request({
url:'/model/getApplyModel',
method:'get',
})
}
//品牌同意或者拒绝模特申请的需求
export function isAgree(isAgree){
return request({
url:'/model/refuseModel',
method:'post',
data:isAgree
})
}

@ -0,0 +1,42 @@
// 封装购物车相关接口
import request from '@/utils/request'
// 加入购物车
export const insertCartAPI = ({ skuId, count }) => {
return request({
url: '/member/cart',
method: 'POST',
data: {
skuId,
count
}
})
}
// 获取最新的购物车列表
export const findNewCartListAPI = () => {
return request({
url: '/member/cart'
})
}
// 删除购物车
export const delCartAPI = (ids) => {
return request({
url: '/member/cart',
method: 'DELETE',
data: {
ids
}
})
}
// 合并购物车
export const mergeCartAPI = (data) => {
return request({
url: '/member/cart/merge',
method: 'POST',
data
})
}

@ -0,0 +1,29 @@
import request from '@/utils/request'
export function getCategoryAPI () {
return request({
url: '/shopping/category',
method:'get',
})
}
/**
* @description: 获取导航数据
* @data {
categoryId: 1005000 ,
page: 1,
pageSize: 20,
sortField: 'publishTime' | 'orderNum' | 'evaluateNum'
}
* @return {*}
*/
export function getSubCategoryAPI (data) {
return request({
url: '/shopping/category/goods',
method: 'get',
data
})
}

@ -0,0 +1,20 @@
import request from '@/utils/request'
export function fetchCommentsByTopicId(topic_Id) {
return request({
url: '/comment/get_comments',
method: 'get',
params: {
topicid: topic_Id
}
})
}
export function pushComment(data) {
return request({
url: '/comment/add_comment',
method: 'post',
data: data
})
}

@ -0,0 +1,83 @@
import request from "@/utils/request";
export function getCourseDirection() {
return request({
url: "/course/direction/show",
method: "get",
});
}
//获取二级分类
export function getCourseCategory() {
return request({
url: "/course/category/show",
method: "get",
});
}
//查询课程标签
export function tagsList(data) {
return request({
url: "/course/tags/list",
method: "get",
data,
});
}
//查询课程
export function searchCourse(pageNo, page, entity) {
return request({
url: "/course/search",
method: "post",
params: {
pageNo: pageNo,
page: page,
},
data: entity,
});
}
//课程详情
export function getCourseDetail(courseId) {
return request({
url: "/course/getDetail",
method: "get",
params: { courseId },
});
}
//课程视频详情
export function getVideoDetail(courseId, videoId) {
return request({
url: "/course/getVideo",
method: "get",
params: {
courseId,
videoId,
},
});
}
//检查是否有权限
export function courseCheckAuth() {
return request({
url: "/course/checkAuth",
method: "get",
});
}
//下载课程资料
export function downloadAttachment(user) {
return request({
url: "/course/downloadAttachment",
params,
responseType: "blob",
});
}
//打卡课程
export function clockIn(courseId) {
return request({
url: "/course/clock",
method: "post",
params: { courseId },
});
}

@ -0,0 +1,25 @@
import request from '@/utils/request'
// 关注
export function follow(id) {
return request(({
url: `/relationship/subscribe/${id}`,
method: 'get'
}))
}
// 关注
export function unFollow(id) {
return request(({
url: `/relationship/unsubscribe/${id}`,
method: 'get'
}))
}
// 验证是否关注
export function hasFollow(topicUserId) {
return request(({
url: `/relationship/validate/${topicUserId}`,
method: 'get'
}))
}

@ -0,0 +1,43 @@
import request from "@/utils/request";
//模特详情
export function getModelDetail(id) {
return request({
url: "/model/getDetail",
method: "get",
params: { id },
});
}
//审核模特数据
export function checkModel(data) {
return request({
url: "/model/check",
method: "post",
data: data,
});
}
//获取申请需求数据
export function applyPost() {
return request({
url: "/model/applyPost",
method: "get",
});
}
//提交模特数据
export function submitModel(form) {
return request({
method: "post",
url: "/model/submitModel",
data: form,
});
}
//获取模特认证要求
export function getModelRequest() {
return request({
method: "get",
url: "/model/identify",
});
}

@ -0,0 +1,193 @@
import request from '@/utils/request'
// 列表
export function getList(pageNo, size, tab) {
return request(({
url: '/post/list',
method: 'get',
params: { pageNo: pageNo, size: size, tab: tab }
}))
}
// 发布
export function post(topic) {
return request({
url: '/post/create',
method: 'post',
data: topic
})
}
// 浏览
export function getTopic(id) {
return request({
url: '/post',
method: 'get',
params: {
id: id
}
})
}
// 获取详情页推荐
export function getRecommendTopics(id) {
return request({
url: '/post/recommend',
method: 'get',
params: {
topicId: id
}
})
}
export function update(topic) {
return request({
url: '/post/update',
method: 'put',
data: topic
})
}
export function deleteTopic(id) {
return request({
url: `/post/delete/${id}`,
method: 'delete'
})
}
//需求申请
export function postApply(modelPost){
return request({
url: '/post/require',
method: 'post',
data:modelPost
})
}
//发布签到数字
export function sendSecretKey(postId,secretKey){
return request({
url: '/post/sendSecretKey',
method: 'put',
params:{
postId,
secretKey
}
})
}
//获取星星名单
export function getStar(id){
return request({
url: '/modelPost/getStar',
method: 'get',
params:{id}
})
}
/**
* 更新星星名单
* @param {*}
* data:{
* modelId:'',
* postId:''
* }
* @returns
*/
export function updateStar(postId,data){
return request({
url: '/modelPost/updateStar',
method: 'put',
data,
params:{postId}
})
}
/**
* 删除星星名单
* @param {*}
* data:{
* modelId:'',
* postId:''
* }
* @returns
*/
export function deleteStar(data){
return request({
url: '/modelPost/deleteStar',
method: 'delete',
data
})
}
/**
* 增加星星名单
* @param {*}
* data:{
* modelId:'',
* postId:''
* }
* @returns
*/
export function addStar(data){
return request({
url: '/modelPost/addStar',
method: 'post',
data
})
}
// 主页获取模特需求
export function getModelRequire(id, page, size) {
return request({
url: '/modelPost/modelRequire/' + id,
method: 'get',
params: {
pageNo: page,
size: size
}
})
}
export function addModelComment(data) {
return request({
url: '/modelComment/add',
method: 'post',
data
})
}
//品牌主页点击评价,获取参与活动的模特名单
export function getPostWithModel(data) {
return request({
url: '/modelPost/get',
method: 'get',
data
})
}
//模特取消申请活动
export function modelRevoke(data) {
return request({
url: '/modelPost/revoke',
method: 'delete',
data
})
}
//模特签到
export function modelSignIn(userId,postId,secretKey) {
return request({
url: '/modelPost/signIn',
method: 'put',
params:{
userId,
postId,
secretKey,
},
})
}
export function modelPost(postId) {
return request({
url: '/modelComment/get',
method: 'get',
params:{
postId,
},
})
}

@ -0,0 +1,9 @@
import request from '@/utils/request'
// 获取推广
export function getList() {
return request(({
url: '/promotion/all',
method: 'get'
}))
}

@ -0,0 +1,14 @@
import request from '@/utils/request'
// 关键词检索
export function searchByKeyword(query) {
return request({
url: `/search`,
method: 'get',
params: {
keyword: query.keyword,
pageNum: query.pageNum,
pageSize: query.pageSize
}
})
}

@ -0,0 +1,12 @@
import request from '@/utils/request'
export function getTopicsByTag(paramMap) {
return request({
url: '/tag/' + paramMap.name,
method: 'get',
params: {
page: paramMap.page,
size: paramMap.size
}
})
}

@ -0,0 +1,8 @@
import request from '@/utils/request'
export function getTodayTip() {
return request({
url: '/tip/today',
method: 'get'
})
}

@ -0,0 +1,43 @@
import request from '@/utils/request'
// 用户主页
export function getInfoByName(username, page, size) {
return request({
url: '/ums/user/' + username,
method: 'get',
params: {
pageNo: page,
size: size
}
})
}
export function getInfo() {
return request({
url: '/ums/user/info',
method: 'get'
})
}
export function getUser(id) {
return request({
url: '/ums/user/getUser',
method: 'get',
params:{
id
}
})
}
// 更新
export function update(user) {
return request({
url: '/ums/user/update',
method: 'post',
data: user
})
}

@ -0,0 +1,153 @@
* {
margin: 0;
padding: 0;
}
body,
html {
background-color: #ffc0cb0d;
color: black;
width: 100%;
font-size: 14px;
letter-spacing: 0.03em;
font-family: -apple-system, BlinkMacSystemFont, Helvetica Neue, PingFang SC,
Microsoft YaHei, Source Han Sans SC, Noto Sans CJK SC, WenQuanYi Micro Hei,
sans-serif, Apple Color Emoji, Segoe UI Emoji, Noto Color Emoji,
Segoe UI Symbol, Android Emoji, EmojiSymbols;
}
/*背景图*/
/*body {*/
/* background-image: url('https://api.mz-moe.cn/img.php');*/
/* background-repeat: round;*/
/*}*/
@media (min-width: 768px) {
.container {
width: 760px;
}
}
@media (min-width: 992px) {
.container {
width: 980px;
}
}
@media (min-width: 1200px) {
.container {
width: 1280px;
}
}
/*滚动条*/
::-webkit-scrollbar {
width: 10px;
height: 10px;
/**/
}
::-webkit-scrollbar-track {
background: rgb(239, 239, 239);
border-radius: 2px;
}
::-webkit-scrollbar-thumb {
background: #bfbfbf;
border-radius: 10px;
}
::-webkit-scrollbar-corner {
background: #179a16;
}
/* 头部 */
.header {
position: fixed;
z-index: 89;
top: 0;
width: 100%;
min-width: 1032px;
background: #fff;
box-shadow: 0 3px 4px rgba(26, 26, 26, 0.1);
height: 54px;
font-size: 16px;
}
a {
color: #1d1d1d;
text-decoration: none;
}
a:hover {
color: #f60;
text-decoration: none !important;
}
.shadow-1 {
box-shadow: 0 0.5em 1em -0.125em rgba(10, 10, 10, 0.1),
0 0 0 1px rgba(10, 10, 10, 0.02);
}
.navbar-dropdown {
font-size: 15px;
}
/*统一卡片样式*/
.el-card {
/*border-radius: 3px !important;*/
margin-bottom: 16px;
/*border: none;*/
}
.my-card {
cursor: pointer;
transition: all 0.1s ease-in-out;
position: relative;
overflow: hidden;
}
.my-card:hover {
transform: scale(1.03);
}
::selection {
text-shadow: none;
background: rgba(67, 135, 244, 0.56);
}
/* 搜索框 */
.search-bar input {
border: none;
box-shadow: none;
}
/*按钮居中*/
.button-center {
display: block;
margin: 0 auto;
}
.ellipsis {
display: block;
white-space: nowrap;
margin: 0 auto;
line-height: 1.4;
-webkit-box-orient: vertical;
overflow: hidden;
text-overflow: ellipsis;
}
.is-ellipsis-1 {
-webkit-line-clamp: 1;
}
.is-ellipsis-2 {
-webkit-line-clamp: 2;
}
.is-ellipsis-3 {
-webkit-line-clamp: 3;
}

@ -0,0 +1,53 @@
/* http://meyerweb.com/eric/tools/css/reset/ */
/* v1.0 | 20080212 */
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, font, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td {
margin: 0;
padding: 0;
border: 0;
outline: 0;
font-size: 100%;
vertical-align: baseline;
background: transparent;
}
body {
line-height: 1;
}
ol, ul {
list-style: none;
}
blockquote, q {
quotes: none;
}
blockquote:before, blockquote:after,
q:before, q:after {
content: '';
content: none;
}
/* remember to define focus styles! */
:focus {
outline: 0;
}
/* remember to highlight inserts somehow! */
ins {
text-decoration: none;
}
del {
text-decoration: line-through;
}
/* tables still need 'cellspacing="0"' in the markup */
table {
border-collapse: collapse;
border-spacing: 0;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 379 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 280 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 207 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 427 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 436 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 123 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 726 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 442 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

@ -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="1702480440616" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6113" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M311.8 169.2L253.6 111C156.4 185.1 92.1 300.2 86 430.4h81.4c6.1-107.8 61.4-202.2 144.4-261.2z m544.8 261.2H938C931.9 300.2 867.6 185 770 111l-58.2 58.2c83.4 59 138.7 153.4 144.8 261.2z m-80.1 20.4c0-124.9-86.7-229.5-203.4-257.1V166c0-33.8-27.3-61-61-61-33.8 0-61 27.3-61 61v27.7c-116.8 27.7-203.4 132.2-203.4 257.1v223.8L166.3 756v40.7H858V756l-81.4-81.4V450.8zM512 918.7c5.7 0 11-0.4 16.3-1.6 26.4-5.3 48.4-23.6 58.6-48 4.1-9.8 6.5-20.3 6.5-31.7H430.6c0 44.7 36.6 81.3 81.4 81.3z m0 0" p-id="6114" fill="#f4ea2a"></path></svg>

After

Width:  |  Height:  |  Size: 860 B

@ -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="1701612728171" class="icon" viewBox="0 0 1205 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1493" xmlns:xlink="http://www.w3.org/1999/xlink" width="235.3515625" height="200"><path d="M1117.16208 822.996942H88.073394a88.269113 88.269113 0 0 1-88.073394-88.073395V107.64526A107.840979 107.840979 0 0 1 107.64526 0h1009.51682a88.269113 88.269113 0 0 1 88.073394 88.073394v646.850153a88.269113 88.269113 0 0 1-88.073394 88.073395zM107.64526 58.715596A48.929664 48.929664 0 0 0 58.715596 107.64526v627.278287a29.357798 29.357798 0 0 0 29.357798 29.357799h1029.088686a29.357798 29.357798 0 0 0 29.357798-29.357799V88.073394a29.357798 29.357798 0 0 0-29.357798-29.357798z" fill="#3D3D3D" p-id="1494"></path><path d="M1032.611621 1024H156.574924a39.143731 39.143731 0 1 1 0-78.287462h876.036697a39.143731 39.143731 0 0 1 0 78.287462z" fill="#F683A2" p-id="1495"></path></svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

@ -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="1701613310734" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5356" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M943.336727 904.890182c-16.290909 13.381818-39.028364 15.592727-57.6 5.655273l-119.389091-49.850182-59.205818 114.129454a51.409455 51.409455 0 0 1-47.662545 32.279273h-0.698182a51.479273 51.479273 0 0 1-48.942546-33.931636l-60.16-163.490909c-29.137455 3.490909-58.577455 3.397818-87.668363-0.302546l-60.253091 163.770182a51.479273 51.479273 0 0 1-48.919273 33.908364h-0.674909c-21.015273 0-39.912727-12.8-47.755636-32.279273L245.294545 860.625455l-119.38909 49.850181a51.944727 51.944727 0 0 1-57.6-5.655272 50.594909 50.594909 0 0 1-15.941819-57.483637l91.973819-249.856a401.873455 401.873455 0 0 1-49.198546-191.301818C102.376727 179.432727 292.119273 1.442909 518.912 8.704c216.599273 6.912 390.586182 180.898909 397.498182 397.498182v-0.046546a401.803636 401.803636 0 0 1-48.872727 192l91.671272 249.181091c7.796364 20.573091 1.396364 43.845818-15.848727 57.506909l-0.023273 0.046546z" fill="#BBA575" p-id="5357"></path><path d="M125.533091 839.866182l106.053818-44.264727a52.689455 52.689455 0 0 1 66.676364 23.924363l52.526545 101.213091 45.521455-123.671273a413.416727 413.416727 0 0 1-206.312728-132.561454l-64.465454 175.36zM505.902545 65.489455C316.741818 64.651636 162.606545 217.088 161.326545 406.248727c0 60.462545 16.221091 119.854545 47.01091 171.892364a346.763636 346.763636 0 0 0 297.658181 168.866909c20.154182 0 40.261818-1.722182 60.16-5.166545 185.483636-30.882909 310.830545-206.312727 279.924364-391.819637A340.503273 340.503273 0 0 0 505.902545 65.489455zM822.132364 665.6a409.297455 409.297455 0 0 1-206.522182 132.002909l45.405091 123.112727 52.503272-101.306181a52.573091 52.573091 0 0 1 66.653091-23.97091l106.123637 44.264728-64.162909-174.126546z" fill="#FFFFFF" p-id="5358"></path><path d="M657.780364 439.202909l8.820363 53.457455a64.512 64.512 0 0 1-26.833454 63.627636 66.280727 66.280727 0 0 1-69.585455 4.189091l-48.221091-25.6-48.64 24.762182a66.164364 66.164364 0 0 1-69.515636-5.538909c-20.247273-14.592-30.254545-39.563636-25.739636-64.093091l9.728-53.248-38.865455-38.144a64.349091 64.349091 0 0 1-16.128-67.072 65.629091 65.629091 0 0 1 53.690182-44.032l54.272-7.284364 24.645818-48.337454a65.698909 65.698909 0 0 1 58.949818-35.886546h0.581818a65.652364 65.652364 0 0 1 58.693819 36.933818l23.761454 48.709818 54.085818 8.378182a65.442909 65.442909 0 0 1 52.945455 44.916364 64.442182 64.442182 0 0 1-17.268364 66.792727l-39.377454 37.469091z" fill="#E9C7A5" p-id="5359"></path><path d="M597.550545 346.368a66.071273 66.071273 0 0 1-49.431272-36.212364l-23.761455-48.663272-24.669091 48.337454a66.024727 66.024727 0 0 1-49.966545 35.281455l-54.295273 7.307636 38.865455 38.097455a64.698182 64.698182 0 0 1 18.501818 57.995636l-9.704727 53.224727 48.64-24.715636a66.187636 66.187636 0 0 1 30.231272-7.261091c10.868364 0 21.573818 2.653091 31.185455 7.703273l48.290909 25.669818-8.797091-53.457455a64.930909 64.930909 0 0 1 19.456-57.6l39.563636-37.469091-54.109091-8.238545z" fill="#FFFFFF" p-id="5360"></path></svg>

After

Width:  |  Height:  |  Size: 3.2 KiB

@ -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="1701612902591" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2524" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M856.357374 220.512253c-1.980097 64.24828-15.792685 126.009925-38.858006 185.838545-27.577079 71.591525-67.953671 134.596488-124.525108 186.656167-4.591575 4.224208-6.031367 8.747221-5.421476 14.697747 1.956561 19.255553 3.52222 38.558178 5.502317 57.81373 4.603855 44.899606-11.06194 81.662905-47.133483 107.74391-38.672788 27.969005-78.923514 53.79623-118.839619 79.993892-25.161053 16.517185-56.087413 1.530866-58.884109-28.429493-3.222391-34.402531-5.755074-68.87567-8.137331-103.346763-1.186012-17.252943-0.725524-17.403369-17.368576-19.612687-44.175105-5.847172-78.750575-26.898627-102.495372-65.09967-12.213159-19.671015-18.267039-41.413202-20.396539-64.259536-0.632403-6.847965-3.384074-8.597819-9.8176-8.954953-35.750225-1.991354-71.476915-4.119831-107.180068-6.813173-29.695323-2.25639-44.750203-33.69031-28.831652-59.920718 11.175527-18.438954 23.077601-36.439934 34.621519-54.660924 12.44238-19.612687 24.780383-39.283702 37.246299-58.872852 22.812565-35.853579 55.69651-55.223742 97.788164-55.56962 24.101931-0.184195 48.248887 4.073782 72.339562 6.675026 4.556783 0.49528 7.791453-0.12689 10.945283-3.660366 55.92573-62.763462 125.146255-105.120153 203.505927-133.456524 44.289716-16.021905 89.868797-26.484188 136.645147-31.318286 23.571858-2.451842 47.305399-3.338025 70.853721 1.035586 12.834306 2.382257 13.490246 2.912329 15.46932 15.492856C855.355557 195.064674 856.920192 207.702506 856.357374 220.512253L856.357374 220.512253zM744.676805 378.992707c0.678452-54.891168-44.600801-102.093213-98.42159-102.978373-55.891961-0.932232-104.302531 39.870056-105.626689 103.577007-1.116427 53.129035 46.822398 101.252055 100.332103 101.620445C697.934225 481.625202 743.973794 436.253852 744.676805 378.992707L744.676805 378.992707zM267.269671 610.950639c10.576893 0.138146 16.447601 4.822842 20.234857 15.676028 14.870686 42.517349 41.930995 74.779124 81.156368 96.648201 8.655124 4.822842 17.783015 8.735965 27.209712 11.95938 16.942881 5.8001 20.809955 22.37459 8.240685 35.127032-18.622126 18.875906-37.44175 37.545104-56.05262 56.410777-6.158257 6.238075-12.93766 9.195429-21.592784 5.961782-8.79327-3.28072-13.041014-9.828856-13.490246-18.968004-0.276293-5.789866-0.138146-11.614525-0.276293-17.425881-0.2415-10.670014-0.345877-10.750855-10.128685-7.504928-20.924565 6.963599-41.804105 13.984503-62.72867 20.936845-6.169513 2.060939-12.361539 2.912329-18.392906-0.517793-8.840342-5.030573-12.177344-14.019295-8.621355-25.080212 6.951319-21.581528 14.238282-43.036165 21.351284-64.559365 3.084245-9.345856 2.888793-9.541307-7.15905-9.701966-6.054903-0.092098-12.131295 0.011256-18.185174-0.287549-8.816806-0.425695-15.089673-4.708232-18.346857-13.087063-3.198855-8.160867-1.151219-15.273868 4.78805-21.281699 19.428491-19.624966 38.950104-39.156812 58.447157-58.712193C257.613754 612.665701 262.217608 610.455359 267.269671 610.950639L267.269671 610.950639z" fill="#252434" p-id="2525"></path></svg>

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 434 KiB

@ -0,0 +1,28 @@
<template>
<el-backtop :bottom="60" :right="60">
<div title="回到顶部"
style="{
height: 100%;
width: 100%;
background-color: #f2f5f6;
box-shadow: 0 1px 0 0;
border-radius: 12px;
text-align: center;
line-height: 40px;
color: #167df0;
}"
>
<i class="fa fa-arrow-up"></i>
</div>
</el-backtop>
</template>
<script>
export default {
name: "BackTop"
}
</script>
<style scoped>
</style>

@ -0,0 +1,58 @@
<template>
<section class="box comments">
<hr />
<h3 class="title is-5">Comments</h3>
<lv-comments-form :slug="slug" v-if="token" @loadComments="fetchComments"/>
<lv-comments-item
v-for="comment in comments"
:key="`comment-${comment.id}`"
:comment="comment"
/>
</section>
</template>
<script>
import { mapGetters } from 'vuex'
import { fetchCommentsByTopicId } from '@/api/comment'
import LvCommentsForm from './CommentsForm'
import LvCommentsItem from './CommentsItem'
export default {
name: 'LvComments',
components: {
LvCommentsForm,
LvCommentsItem
},
data() {
return {
comments: []
}
},
props: {
slug: {
type: String,
default: null
}
},
computed: {
...mapGetters([
'token'
])
},
async mounted() {
await this.fetchComments(this.slug)
},
methods: {
//
async fetchComments(topic_id) {
console.log(topic_id)
fetchCommentsByTopicId(topic_id).then(response => {
const { data } = response
this.comments = data
console.log(this.comments)
})
}
}
}
</script>

@ -0,0 +1,70 @@
<template>
<article class="media">
<div class="media-content">
<form @submit.prevent="onSubmit">
<b-field>
<b-input
v-model.lazy="commentText"
type="textarea"
maxlength="400"
placeholder="Add a comment..."
:disabled="isLoading"
></b-input>
</b-field>
<nav class="level">
<div class="level-left">
<b-button
type="is-primary"
native-type="submit"
class="level-item"
:disabled="isLoading"
>
Comment
</b-button>
</div>
</nav>
</form>
</div>
</article>
</template>
<script>
import { pushComment } from '@/api/comment'
export default {
name: 'LvCommentsForm',
data() {
return {
commentText: '',
isLoading: false
}
},
props: {
slug: {
type: String,
default: null
}
},
methods: {
async onSubmit() {
this.isLoading = true
try {
let postData = {}
console.log(this.commentText)
postData['content'] = this.commentText
postData['topic_id'] = this.slug
await pushComment(postData)
this.$emit('loadComments', this.slug)
this.$message.success('留言成功')
} catch (e) {
this.$buefy.toast.open({
message: `Cannot comment this story. ${e}`,
type: 'is-danger'
})
} finally {
this.isLoading = false
}
}
}
}
</script>

@ -0,0 +1,32 @@
<template>
<article class="media">
<figure class="media-left image is-48x48">
<img :src=comment.avatar>
</figure>
<div class="media-content">
<div class="content">
<p>
<strong>{{ comment.username }}</strong>
<small class="ml-2">{{ comment.createTime | date }}</small>
<br />
{{ comment.content }}
</p>
</div>
</div>
</article>
</template>
<script>
export default {
name: 'LvCommentsItem',
props: {
comment: {
type: Object,
required: true
}
}
}
</script>

@ -0,0 +1,60 @@
<template>
<footer class="footer has-text-grey-light has-background-grey-darker">
<div class="container">
<div class="">
<span>我们提供桥梁连接模特梦想与现实的距离</span>
<span style="float: right">
<router-link :to="{path:'/admin/login'}">
管理员登录
</router-link>
|
<a href="/?lang=zh_CN">中文</a> |
<a href="/?lang=en_US">English</a>
</span>
</div>
<div>
<span>{{ title }} ALL RIGHTS RESERVED</span>
<div style="float: right">
<template>
<b-taglist attached>
<b-tag type="is-dark" size="is-normal">Design</b-tag>
<b-tag type="is-info" size="is-normal">{{ author }}</b-tag>
</b-taglist>
</template>
</div>
</div>
</div>
<back-top></back-top>
</footer>
</template>
<script>
import BackTop from "@/components/Backtop/BackTop";
export default {
name: "Footer",
components: {
BackTop
},
data() {
return {
title: "© " + new Date().getFullYear() + ' 童星闪耀',
author: '深藏blue队',
};
},
};
</script>
<style scoped>
footer {
margin-top: 120px;
height: 150px;
}
footer a{
color: #bfbfbf;
}
</style>

@ -0,0 +1,625 @@
<template>
<header class="header has-background-white has-text-black">
<b-navbar class="container is-white" :fixed-top="true">
<template slot="brand">
<b-navbar-item tag="router-link" :to="{ path: '/' }">
<img :src="doubaoImg" alt="logo">
</b-navbar-item>
<b-navbar-item class="is-hidden-desktop" tag="router-link" :to="{ path: '/' }">
主页
</b-navbar-item>
</template>
<template slot="start">
<b-navbar-item tag="router-link" :to="{ path: '/' }" @click="activeIndex = 1"
style="margin-right: 20px;margin-left: 20px;" exact-active-class="Active">
<img src="../../assets/image/需求发布.svg" alt="" style="width: 20px;">需求匹配
</b-navbar-item>
<!-- 培训视频 -->
<b-navbar-item @click="activeIndex = 2" exact-active-class="Active" tag="router-link" style="margin-right: 20px;"
:to="{ path: '/course' }">
<img src="../../assets/image/视频.svg" alt="" style="width: 20px;margin-right: 5px;">培训视频
</b-navbar-item>
<!-- 童星认证 -->
<b-navbar-item @click="activeIndex = 3" tag="router-link" exact-active-class="Active" style="margin-right: 20px;"
:to="{ path: '/certification' }">
<img src="../../assets/image/资质.svg" alt="" style="width: 20px;margin-right: 5px;">童星认证
</b-navbar-item>
<!-- 会员 -->
<b-navbar-item @click="activeIndex = 4" tag="router-link" exact-active-class="Active" :to="{ path: '/member' }">
<img src="../../assets/image/开通会员.png" alt="" style="width: 20px;margin-right: 5px;">我的会员
</b-navbar-item>
<b-navbar-item @click="activeIndex = 5" tag="router-link" exact-active-class="Active" :to="{ path: '/shopping' }">
<img src="../../assets/image/商场.png" alt="" style="width: 20px;">童星服饰
</b-navbar-item>
</template>
<template slot="end">
<b-navbar-item tag="div">
<b-field position="is-centered">
<b-input v-model="searchKey" class="s_input" width="80%" placeholder="搜索需求、标签和用户" rounded clearable
@keyup.enter.native="search()" />
<p class="control">
<b-button class="is-info" @click="search()">
</b-button>
</p>
</b-field>
</b-navbar-item>
<b-navbar-item tag="div">
<b-switch v-model="darkMode" passive-type="is-warning" type="is-dark">
{{ darkMode ? "夜" : "日" }}
</b-switch>
</b-navbar-item>
<b-navbar-item v-if="token == null || token === ''" tag="div">
<div class="buttons">
<b-button class="is-light" tag="router-link" :to="{ path: '/register' }">
注册
</b-button>
<b-button class="is-light" tag="router-link" :to="{ path: '/login' }">
登录
</b-button>
</div>
</b-navbar-item>
<b-navbar-dropdown v-else :label="user.alias">
<b-navbar-item tag="router-link" :to="{ path: `/member/${user.username}/home` }">
🧘 个人中心
</b-navbar-item>
<hr class="dropdown-divider">
<b-navbar-item tag="router-link" :to="{ path: `/member/${user.username}/setting` }">
设置中心
</b-navbar-item>
<hr class="dropdown-divider">
<b-navbar-item tag="a" @click="logout"> 👋 退
</b-navbar-item>
</b-navbar-dropdown>
<b-navbar-item tag="div">
<el-badge :value="requestList.length" class="item" style="margin-top: 5px;">
<img src="../../assets/image/消息.svg" style="cursor: pointer;" @click="getMessage">
</el-badge>
</b-navbar-item>
<el-drawer :visible.sync="drawerVisible" title="消息列表" size="600px" :with-header="false" :append-to-body="true"
@before-close="handleDrawerClose">
<div v-if="userInfo.roleId == 2">
<el-table :data="requestList" style="width: 100%">
<el-table-column label="需求申请">
<el-table-column label="需求名称" prop="postName"></el-table-column>
<el-table-column label="申请模特">
<template slot-scope="scope">
<el-link @click="showModelDetails(scope.row.model)" type="primary">{{ scope.row.model.actualName
}}</el-link>
</template>
</el-table-column>
<el-table-column label="申请理由" prop="applyDetail"></el-table-column>
<el-table-column label="操作">
<template slot-scope="scope">
<div class="button-group">
<el-button @click="acceptRequest(scope.row)" type="success" size="mini">接受</el-button>
<el-button @click="rejectRequest(scope.row)" type="danger" size="mini">拒绝</el-button>
</div>
</template>
</el-table-column>
</el-table-column>
</el-table>
<el-table :data="messageList" style="width: 100%;">
<el-table-column label="消息30天后自动清除" prop="content"></el-table-column>
</el-table>
</div>
<div v-else>
<el-table :data="requestList" style="width: 100%">
<el-table-column label="消息30天后自动清除" prop="content"></el-table-column>
</el-table>
</div>
<el-dialog :visible.sync="modelDetailsVisible" title="模特详情" width="30%" :modal="false">
<p>姓名: {{ selectedModel.actualName }}</p>
<p>性别: {{ selectedModel.sex }}</p>
<p>年龄: {{ selectedModel.age }} </p>
<p>身高: {{ selectedModel.height }} cm</p>
<p>体重: {{ selectedModel.weight }} kg</p>
<p>星级:
<span v-for="star in selectedModel.level" :key="star">
<i class="el-icon-star-on"></i>
</span>
</p>
<p>邮箱: {{ selectedModel.email }}</p>
</el-dialog>
<el-dialog :visible.sync="starListDialogVisible" title="星星名单" @close="handleCloseDialog" :modal="false">
<!-- 男童星入选名单 -->
<div class="drag-list">
<p>男童星入选名单</p>
<draggable v-model="selectedStars" :options="{ group: 'maleStars' }" @start="handleDragStart"
@end="handleDragStop" @change="handleUpdate">
<div v-for="star in selectedStars" :key="star.id" class="star-item" @click="showModelDetails(star)">
<i class="el-icon-star-on star-handle"></i>
<span class="clickable">{{ star.actualName }}</span>
<el-button @click="confirmReplacement(star)" type="primary" size="mini">确定替代</el-button>
</div>
</draggable>
<p>男童星候选名单(最多2名候选者)</p>
<draggable v-model="candidates" :options="{ group: 'maleStars' }" @start="handleDragStart"
@end="handleDragStop" @change="handleUpdate">
<div v-for="(star, index) in candidates" :key="index" class="star-item">
<i class="el-icon-star-on star-handle"></i>
<span class="clickable">{{ star.actualName }}</span>
<el-button @click="confirmReplacement(star)" type="primary" size="mini">确定替代</el-button>
</div>
</draggable>
</div>
<div class="drag-list">
<p>女童星入选名单</p>
<draggable v-model="selectedFemaleStars" :options="{ group: 'femaleStars' }" @start="handleDragStart"
@end="handleDragStop" @change="handleUpdate">
<div v-for="star in selectedFemaleStars" :key="star.id" class="star-item" @click="showModelDetails(star)">
<i class="el-icon-star-on star-handle"></i>
<span class="clickable">{{ star.actualName }}</span>
<el-button @click="confirmReplacement(star)" type="primary" size="mini">确定替代</el-button>
</div>
</draggable>
<p>女童星候选名单(最多2名候选者)</p>
<draggable v-model="femaleCandidates" :options="{ group: 'femaleStars' }" @start="handleDragStart"
@end="handleDragStop" @change="handleUpdate">
<div v-for="star in femaleCandidates" :key="star.id" class="star-item" @click="showModelDetails(star)">
<i class="el-icon-star-on star-handle"></i>
<span class="clickable">{{ star.actualName }}</span>
<el-button @click="confirmReplacement(star)" type="primary" size="mini">确定替代</el-button>
</div>
</draggable>
</div>
<div style="text-align: center; margin-top: 20px;">
<el-button @click="handleSave" type="primary">保存</el-button>
</div>
</el-dialog>
</el-drawer>
</template>
</b-navbar>
</header>
</template>
<script>
import { disable as disableDarkMode, enable as enableDarkMode } from 'darkreader'
import { getDarkMode, setDarkMode } from '@/utils/auth'
import { getInfo } from '@/api/user'
import { isAgree } from '@/api/brand'
import { getApplyModel } from '@/api/brand'
import { getStar, updateStar } from '@/api/post'
import { applyPost } from '@/api/model'
import { mapGetters } from 'vuex'
import draggable from 'vuedraggable';
export default {
name: 'Header',
components: { draggable },
data() {
return {
userInfo: [],
drawerVisible: false,
requestList: [],//
messageList: [],//
modelDetailsVisible: false, //
selectedModel: {},
activeIndex: 1, //
logoUrl: require('@/assets/logo.png'),
doubaoImg: require('@/assets/image/logo2(1).png'),
searchKey: '',
darkMode: false,
ageeOrReject: {
userId: '',
postId: '',
},
selectedStars: [
{ id: 1, actualName: 'Star 1' },
{ id: 2, actualName: 'Star 2' },
],
candidates: [
{ id: 3, actualName: 'Candidate 1' },
{ id: 4, actualName: 'Candidate 2' },
{ id: 9, actualName: 'Candidate 3' },
{ id: 10, actualName: 'Candidate 4' },
{ id: 11, actualName: 'Candidate 5' },
],
selectedFemaleStars: [
{ id: 5, actualName: 'Female Star 1' },
{ id: 6, actualName: 'Female Star 2' },
],
femaleCandidates: [
{ id: 7, actualName: 'Female Candidate 1' },
{ id: 8, actualName: 'Female Candidate 2' },
{ id: 12, actualName: 'Female Candidate 3' },
{ id: 13, actualName: 'Female Candidate 4' },
{ id: 14, actualName: 'Female Candidate 5' },
],
maleCount:'',
femaleCount:'',
postModel:{},//
backups: {
selectedStars: [],
candidates: [],
selectedFemaleStars: [],
femaleCandidates: [],
},
//
candidatesBackup: [],
selectedStarsBackup: [],
femaleCandidatesBackup: [],
femaleSelectedStarsBackup: [],
//
starListDialogVisible: false,
//
candidatesChanged: false,
replacementModel: null, //
closingForModelDetails: false, //
}
},
computed: {
...mapGetters(['token', 'user'])
},
watch: {
// Theme
darkMode(val) {
if (val) {
enableDarkMode({})
} else {
disableDarkMode()
}
setDarkMode(this.darkMode)
}
},
beforeMount() {
this.info()
},
created() {
// cookie
this.darkMode = getDarkMode()
if (this.darkMode) {
enableDarkMode({})
} else {
disableDarkMode()
}
},
methods: {
showModelDetails(model) {
this.selectedModel = model;
this.modelDetailsVisible = true;
},
handleDragStart() {
//
this.candidatesBackup = this.candidates;
this.selectedStarsBackup = this.selectedStars;
this.femaleCandidatesBackup = this.femaleCandidates,
this.femaleSelectedStarsBackup = this.selectedFemaleStars
},
handleDragStop(e) {
if (e.pullMode !== null) { //
this.candidatesChanged = true;
}
},
handleUpdate(e) {
if(this.selectedStars.length>this.maleCount){
this.$message.warning('入选名单人数不能超过需求人数!');
this.candidates = this.candidatesBackup;
this.selectedStars = this.selectedStarsBackup
}
if(this.selectedFemaleStars.length>this.femaleCount){
this.$message.warning('入选名单人数不能超过需求人数!');
this.femaleCandidates = this.femaleCandidatesBackup;
this.selectedFemaleStars = this.femaleSelectedStarsBackup
}
// 5
if (this.candidates.length > 2) {
//
this.$message.warning('候选名单不能超过2人');
//
this.candidates = this.candidatesBackup;
this.selectedStars = this.selectedStarsBackup
// e.draggedContext.newIndex = e.draggedContext.oldIndex;
}
if (this.femaleCandidates.length > 2) {
this.$message.warning('候选名单不能超过2人');
//
this.femaleCandidates = this.femaleCandidatesBackup;
this.selectedFemaleStars = this.femaleSelectedStarsBackup
}
//
return true;
},
handleSave() {
this.postModel={
selectedStars:this.selectedStars,
candidates:this.candidates,
selectedFemaleStars:this.selectedFemaleStars,
femaleCandidates:this.femaleCandidates,
},
updateStar(
this.ageeOrReject.postId,
this.postModel
).then(res=>{
console.log(res);
})
// candidates femaleCandidates
this.candidatesChanged = false; //
this.starListDialogVisible = false; //
this.$message.success("保存成功")
},
//
handleCloseDialog() {
console.log(this.candidatesChanged)
if (this.candidatesChanged) {
//
this.$confirm('您有未保存的更改,是否保存?', '提示', {
confirmButtonText: '保存',
cancelButtonText: '不保存',
type: 'warning',
}).then(() => {
this.postModel={
selectedStars:this.selectedStars,
candidates:this.candidates,
selectedFemaleStars:this.selectedFemaleStars,
femaleCandidates:this.femaleCandidates,
},
//
this.handleSave();
}).catch(() => {
//
this.selectedStars = this.backups.selectedStars;
this.candidates = this.backups.candidates;
this.selectedFemaleStars = this.backups.selectedFemaleStars;
this.femaleCandidates = this.backups.femaleCandidates;
this.candidatesChanged = false; //
this.starListDialogVisible = false; //
});
} else {
//
this.starListDialogVisible = false;
}
},
confirmReplacement(model) {
//
this.$confirm("此操作将此模特移出此活动, 是否继续?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
}).then(() => {
console.log(121)
model=this.replacementModel;
this.$message.success('替代成功')
}).catch(() => {
this.$message({
type: "info",
message: "已取消",
});
});
//
this.replacementModel = null;
},
getMessage() {
this.drawerVisible = true;
},
info() {
if (this.token != null && this.token != '') {
getInfo().then((res) => {
this.userInfo = res.data;
if (res.data.roleId == 2) {
getApplyModel().then(res => {
this.requestList = res.data;
console.log(this.requestList)
});
applyPost().then(res => {
this.messageList = res.data;
})
}
else {
applyPost().then(res => {
this.requestList = res.data;
})
}
});
}
},
acceptRequest(row) {
// Handle logic for accepting the request
console.log('接受请求:', row);
getStar(row.postId).then(res=>{
this.selectedStars = res.data.selectedStars;
this.candidates = res.data.candidates;
this.selectedFemaleStars = res.data.selectedFemaleStars;
this.femaleCandidates = res.data.femaleCandidates;
})
this.backups.selectedStars = [...this.selectedStars];
this.backups.candidates = [...this.candidates];
this.backups.selectedFemaleStars = [...this.selectedFemaleStars];
this.backups.femaleCandidates = [...this.femaleCandidates];
this.starListDialogVisible = true;
this.maleCount=row.maleCount;
this.femaleCount=row.femaleCount;
this.replacementModel=row.model
this.starListDialogVisible=true;
this.info();
this.ageeOrReject.userId = row.model.userId,
this.ageeOrReject.postId = row.postId
},
rejectRequest(row) {
// Handle logic for rejecting the request
this.ageeOrReject.userId = row.model.userId,
this.ageeOrReject.postId = row.postId,
isAgree(this.ageeOrReject).then(res => {
this.$message.success(res.message)
})
this.info()
},
showModelDetails(model) {
this.selectedModel = model;
if (!this.closingForModelDetails) {
this.modelDetailsVisible = true;
}
},
handleDrawerClose(done) {
// Set a flag to indicate the closing reason
this.closingForModelDetails = false;
// Logic when closing the drawer
// If you want to prevent the drawer from closing, you can use done(false)
done();
},
setActive(index) {
this.activeIndex = index;
},
async logout() {
this.$store.dispatch('user/logout').then(() => {
this.$message.info('退出登录成功')
setTimeout(() => {
this.$router.push({ path: this.redirect || '/' })
}, 500)
})
},
search() {
console.log(this.token)
if (this.searchKey.trim() === null || this.searchKey.trim() === '') {
this.$message.info({
showClose: true,
message: '请输入关键字搜索!',
type: 'warning'
})
return false
}
this.$router.push({ path: '/search?key=' + this.searchKey })
}
}
}
</script>
<style scoped>
.star-item .el-button {
margin-left: auto;
}
.star-item {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 10px;
}
.star-handle {
cursor: grab;
margin-right: 10px;
}
.el-icon-star-on {
color: gold;
}
.button-group {
display: flex;
align-items: center;
justify-content: center;
}
.button-group el-button {
margin-right: 5px;
}
input {
width: 80%;
height: 86%;
}
.Active {
border-bottom: 1px solid transparent;
border-width: 3px;
border-color: rgb(103, 144, 233);
}
@media screen and (min-width: 1024px) {
.navbar.is-white .navbar-start>.navbar-item,
.navbar.is-white .navbar-start .navbar-link {
font-family: "Dank Mono", ui-monospace, monospace;
background: linear-gradient(to right,
hsl(98 100% 62%),
hsl(204 100% 59%));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
.navbar.is-white .navbar-end>.navbar-item,
.navbar.is-white .navbar-end .navbar-link {
color: rgba(255, 192, 203, 0.779);
}
}
</style>

@ -0,0 +1,103 @@
<template>
<div :class="{ hidden: hidden }" class="pagination-container">
<el-pagination
:background="background"
:current-page.sync="currentPage"
:page-size.sync="pageSize"
:layout="layout"
:page-sizes="pageSizes"
:total="total"
v-bind="$attrs"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
</div>
</template>
<script>
import {scrollTo} from "@/utils/scroll-to";
export default {
name: "Pagination",
props: {
total: {
required: true,
type: Number,
},
page: {
type: Number,
default: 1,
},
limit: {
type: Number,
default: 10,
},
pageSizes: {
type: Array,
default() {
return [5, 10, 20, 30, 50];
},
},
layout: {
type: String,
default: "total, sizes, prev, pager, next, jumper",
// default: 'sizes, prev, pager, next, jumper'
},
background: {
type: Boolean,
default: true,
},
autoScroll: {
type: Boolean,
default: true,
},
hidden: {
type: Boolean,
default: false,
},
},
computed: {
currentPage: {
get() {
return this.page;
},
set(val) {
this.$emit("update:page", val);
},
},
pageSize: {
get() {
return this.limit;
},
set(val) {
this.$emit("update:limit", val);
},
},
},
methods: {
handleSizeChange(val) {
this.$emit("pagination", { page: this.currentPage, limit: val });
if (this.autoScroll) {
scrollTo(0, 800);
}
},
handleCurrentChange(val) {
this.$emit("pagination", { page: val, limit: this.pageSize });
if (this.autoScroll) {
scrollTo(0, 800);
}
},
},
};
</script>
<style scoped>
.pagination-container {
/* background: #fff; */
padding: 5px 0px;
}
.pagination-container.hidden {
display: none;
}
</style>

@ -0,0 +1,41 @@
<template>
<div class="comment">
<div class="comment-info">
<span class="comment-user">{{ comment.name }}</span>
<span class="comment-time">{{ comment.time }}</span>
</div>
<p class="comment-content">{{ comment.content }}</p>
</div>
</template>
<script>
export default {
props: {
comment: {
type: Object,
required: true,
},
},
};
</script>
<style scoped>
/* 样式可以根据需要进行调整 */
.comment {
margin-bottom: 15px;
}
.comment-info {
color: #888;
font-size: 12px;
margin-bottom: 5px;
}
.comment-user {
margin-right: 5px;
}
.comment-content {
font-size: 14px;
}
</style>

@ -0,0 +1,25 @@
// 定义懒加载指令
const lazyLoadDirective = {
// 指令的定义
bind(el, binding) {
// 使用 Intersection Observer 监听元素是否进入视口
const observer = new IntersectionObserver(entries => {
const { isIntersecting } = entries[0];
if (isIntersecting) {
// 当元素进入视口时,加载图片
el.src = binding.value;
observer.disconnect(); // 停止监听
}
});
// 将元素添加到 Intersection Observer 中进行监听
observer.observe(el);
},
};
// 在 Vue 2 中注册懒加载指令
export default {
install(Vue) {
Vue.directive('lazy', lazyLoadDirective);
},
};

@ -0,0 +1,44 @@
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
// Buefy
import Buefy from 'buefy'
import 'buefy/dist/buefy.css'
// ElementUI
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import '@/assets/app.css'
import './assets/plugins/font-awesome-4.7.0/css/font-awesome.min.css'
import format from 'date-fns/format'
import '@/permission'
import relativeTime from 'dayjs/plugin/relativeTime';
import LazyLoadDirective from '@/directives'
// 国际化
import 'dayjs/locale/zh-cn'
const dayjs = require('dayjs');
// 相对时间插件
dayjs.extend(relativeTime)
dayjs.locale('zh-cn') // use locale globally
dayjs().locale('zh-cn').format() // use locale in a specific instance
Vue.prototype.dayjs = dayjs;//可以全局使用dayjs
Vue.filter('date', (date) => {
return format(new Date(date), 'yyyy-MM-dd')
})
Vue.use(Buefy)
Vue.use(ElementUI);
Vue.use(LazyLoadDirective)
Vue.config.productionTip = false
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')

@ -0,0 +1,41 @@
import router from './router'
import store from './store'
import getPageTitle from '@/utils/get-page-title'
import NProgress from 'nprogress' // progress bar
import 'nprogress/nprogress.css'
import {getToken} from "@/utils/auth"; // progress bar style
NProgress.configure({showSpinner: false}) // NProgress Configuration
router.beforeEach(async (to, from, next) => {
// start progress bar
NProgress.start()
// set page title
document.title = getPageTitle(to.meta.title)
// determine whether the user has logged in
const hasToken = getToken();
if (hasToken) {
if (to.path === '/login') {
// 登录,跳转首页
next({path: '/'})
NProgress.done()
} else {
// 获取用户信息
await store.dispatch('user/getInfo')
next()
}
} else if (!to.meta.requireAuth)
{
next()
}
else {
next('/login')
}
})
router.afterEach(() => {
// finish progress bar
NProgress.done()
})

@ -0,0 +1,140 @@
import Vue from "vue";
import VueRouter from "vue-router";
Vue.use(VueRouter);
const routes = [
{
path: "/",
name: "Home",
component: () => import("@/views/Home"),
},
{
path: "/course",
component: () => import("@/views/Course"),
meta: { title: "课程" },
},
{
path: "/course/:id",
component: () => import("@/views/CourseInfo"),
meta: { title: "课程详情" },
},
{
path: "/courseStudy/:courseId/:itemId",
component: () => import("@/views/CourseStudy"),
meta: { title: "课程章节学习",requireAuth: true },
},
{
path: "/certification",
component: () => import("@/views/Certification"),
meta: { title: "童星认证",requireAuth: true },
},
{
path: "/member",
component: () => import("@/views/Member"),
meta: { title: "我的会员",requireAuth: true },
},
{
path: "/shopping",
component: () => import("@/views/shop/Category/Clothes"),
meta: { title: "童星服饰"},
},
{
path: "/shopping/category/:id",
component: () => import("@/views/shop/SubCategory/SubCategory"),
meta: { title: "服饰分类" },
},
{
path: "/clothesDetail/:id",
component: () => import("@/views/shop/Detail/index"),
meta: { title: "服饰详情" },
},
{
path: "/register",
name: "register",
component: () => import("@/views/auth/Register"),
meta: { title: "注册" },
},
// 登录
{
name: "login",
path: "/login",
component: () => import("@/views/auth/Login"),
meta: { title: "登录" },
},
// 发布
{
name: "post-create",
path: "/post/create",
component: () => import("@/views/post/Create"),
meta: { title: "信息发布", requireAuth: true },
},
// 编辑
{
name: 'topic-edit',
path: '/topic/edit/:id',
component: () => import('@/views/post/Edit'),
meta: {
title: '编辑',
requireAuth: true
}
},
// 详情
{
name: "post-detail",
path: "/post/:id",
component: () => import("@/views/post/Detail"),
meta: { title: "详情" },
},
{
name: 'tag',
path: '/tag/:name',
component: () => import('@/views/tag/Tag'),
meta: { title: '主题列表' }
},
// 检索
{
name: 'search',
path: '/search',
component: () => import('@/views/Search'),
meta: { title: '检索' }
},
// 用户主页
{
name: 'user',
path: '/member/:username/home',
component: () => import('@/views/user/Profile'),
meta: { title: '用户主页' }
},
// 用户设置
{
name: 'user-setting',
path: '/member/:username/setting',
component: () => import('@/views/user/Setting'),
meta: { title: '设置', requireAuth: true }
},
{
path: "/404",
name: "404",
component: () => import("@/views/error/404"),
meta: { title: "404-NotFound" },
},
// {
// path: "*",
// redirect: "/404",
// hidden: true,
// },
];
const originalPush = VueRouter.prototype.push;
VueRouter.prototype.push = function push(location) {
return originalPush.call(this, location).catch((err) => err);
};
const router = new VueRouter({
routes,
});
export default router;

@ -0,0 +1,32 @@
// store/cart.js
export default {
state: {
cartList: [],
},
mutations: {
updateCartList(state, newList) {
state.cartList = newList;
},
addCartItem(state,cartItem){
state.cartList=cartItem;
}
},
actions: {
// 如果需要异步加载购物车数据,可以在此处调用 API
// 然后提交 mutation 更新购物车数据
// updateCartListAction(context) {
// const res = await fetchCartData();
// context.commit('updateCartList', res.data);
// },
},
getters : {
allCount: (state) => state.cartList.reduce((a, c) => a + c.count, 0),
allPrice: (state) => state.cartList.reduce((a, c) => a + c.count * c.price, 0),
selectedCount: (state) => state.cartList.filter(item => item.selected).reduce((a, c) => a + c.count, 0),
selectedPrice: (state) => state.cartList.filter(item => item.selected).reduce((a, c) => a + c.count * c.price, 0),
isAll: (state) => state.cartList.every((item) => item.selected),
}
};

@ -0,0 +1,5 @@
const getters = {
token: state => state.user.token, // token
user: state => state.user.user, // 用户对象
}
export default getters

@ -0,0 +1,18 @@
import Vue from 'vue'
import Vuex from 'vuex'
import getters from './getters'
import cartList from './cartStore'
import user from './modules/user'
Vue.use(Vuex)
const store = new Vuex.Store({
modules: {
user,
cartList
},
getters
})
export default store

@ -0,0 +1,87 @@
import { getUserInfo, login, logout } from "@/api/auth/auth";
import { getToken, setToken, removeToken } from "@/utils/auth";
const state = {
token: getToken(), // token
user: "", // 用户对象
};
const mutations = {
SET_TOKEN_STATE: (state, token) => {
state.token = token;
},
SET_USER_STATE: (state, user) => {
state.user = user;
},
};
const actions = {
// 用户登录
login({ commit }, userInfo) {
console.log(userInfo);
const { name, pass, rememberMe } = userInfo;
return new Promise((resolve, reject) => {
login({ username: name.trim(), password: pass, rememberMe: rememberMe })
.then((response) => {
const { data } = response;
commit("SET_TOKEN_STATE", data.token);
setToken(data.token);
resolve();
setTimeout(() => {
window.location.reload();
}, 500);
})
.catch((error) => {
reject(error);
});
});
},
// 获取用户信息
getInfo({ commit, state }) {
return new Promise((resolve, reject) => {
getUserInfo()
.then((response) => {
const { data } = response;
if (!data) {
commit("SET_TOKEN_STATE", "");
commit("SET_USER_STATE", "");
removeToken();
resolve();
reject("Verification failed, please Login again.");
}
commit("SET_USER_STATE", data);
resolve(data);
})
.catch((error) => {
reject(error);
});
});
},
// 注销
async logout({ commit, state }) {
return new Promise((resolve, reject) => {
logout(state.token)
.then((response) => {
console.log(response);
commit("SET_TOKEN_STATE", "");
commit("SET_USER_STATE", "");
removeToken();
resolve();
setTimeout(() => {
window.location.reload();
}, 500);
})
.catch((error) => {
reject(error);
});
});
},
};
export default {
namespaced: true,
state,
mutations,
actions,
};

@ -0,0 +1,30 @@
import request from '@/utils/request'
// 用户主页
export function getInfoByName(username, page, size) {
return request({
url: '/ums/user/' + username,
method: 'get',
params: {
pageNo: page,
size: size
}
})
}
// 用户主页
export function getInfo() {
return request({
url: '/ums/user/info',
method: 'get'
})
}
// 更新
export function update(user) {
return request({
url: '/ums/user/update',
method: 'post',
data: user
})
}

@ -0,0 +1,44 @@
import request from './request'
//获取购物车商品
export function getShopCarList(){
return request({
url:'/api/shopcar/getShopCarList',
})
}
//删除购物车
export function deleteShopCar( params , token ){
return request({
url:'/api/shopcar/deleteShopCar',
params,
headers:{
token
}
})
}
//删除购物车[批量]
export function deleteShopCars( ids, token ){
return request({
url:'/api/shopcar/deleteShopCars',
method: 'POST',
data:ids,
headers:{
token
}
})
}
//加入购物车
export function addShopCar( data , token ){
return request({
url:'/api/shopcar/addShopCar',
method:'post',
data,
headers:{
token
}
})
}

@ -0,0 +1,8 @@
import request from './request'
//创建Token
export function createToken(){
return request({
url:'/api/token/createToken',
})
}

@ -0,0 +1,44 @@
import request from './request'
//用户名密码登录
export function loginByJson( data ){
return request({
url:'/api/u/loginByJson',
method:'post',
data
})
}
//发送注册或登录验证码
export function sendCaptcha( params ){
return request({
url:'/api/sms/sendRegisterOrLoginCaptcha',
params
})
}
//手机验证码登录
export function loginByMobile( data ){
return request({
url:'/api/u/loginByMobile',
method:'post',
data
})
}
//获取个人信息
export function getInfo( params ){
return request({
url:'/api/member/getInfo',
params
})
}
//退出登录
export function logout(){
return request({
url:'/api/u/logout'
})
}

@ -0,0 +1,47 @@
import request from './request'
//去结算
export function settlement( data ){
return request({
url:'/api/order/settlement',
method:"post",
data
})
}
//支付宝结算
export function alipayOrder( data ){
return request({
url:'/api/pay/alipay/createOrder',
method:"post",
data
})
}
//查询支付宝,支付订单状态
export function queryAlipay( params ){
return request({
url:'/api/pay/alipay/queryOrder',
params
})
}
//微信结算
export function wxpayOrder( data ){
return request({
url:'/api/pay/wxpay/createOrder',
method:"post",
data
})
}
//查询微信,支付订单状态
export function queryWxpay( params ){
return request({
url:'/api/pay/wxpay/queryOrder',
params
})
}

@ -0,0 +1,31 @@
import Cookies from 'js-cookie'
const uToken = 'u_token'
const darkMode = 'dark_mode';
// 获取Token
export function getToken() {
return Cookies.get(uToken);
}
// 设置Token1天,与后端同步
export function setToken(token) {
return Cookies.set(uToken, token, {expires: 1})
}
// 删除Token
export function removeToken() {
return Cookies.remove(uToken)
}
export function removeAll() {
return Cookies.Cookies.removeAll()
}
export function setDarkMode(mode) {
return Cookies.set(darkMode, mode, {expires: 365})
}
export function getDarkMode() {
return !(undefined === Cookies.get(darkMode) || 'false' === Cookies.get(darkMode));
}

@ -0,0 +1,8 @@
const title = '童星闪耀'
export default function getPageTitle(pageTitle) {
if (pageTitle) {
return `${pageTitle} - ${title}`
}
return `${title}`
}

@ -0,0 +1,81 @@
import axios from 'axios'
import { Message, MessageBox } from 'element-ui'
import store from '@/store'
import { getToken } from '@/utils/auth'
// 1.创建axios实例
const service = axios.create({
// 公共接口--这里注意后面会讲,url = base url + request url
baseURL: process.env.VUE_APP_SERVER_URL,
// baseURL: 'https://api.example.com',
// 超时时间 单位是ms这里设置了20s的超时时间
timeout: 20 * 1000
})
// 2.请求拦截器request interceptor
service.interceptors.request.use(
config => {
// 发请求前做的一些处理数据转化配置请求头设置token,设置loading等根据需求去添加
// 注意使用token的时候需要引入cookie方法或者用本地localStorage等方法推荐js-cookie
if (store.getters.token) {
// config.params = {'token': token} // 如果要求携带在参数中
// config.headers.token = token; // 如果要求携带在请求头中
// bearerw3c规范
config.headers['Authorization'] = 'Bearer ' + getToken()
}
return config
},
error => {
// do something with request error
// console.log(error) // for debug
return Promise.reject(error)
}
)
// 设置cross跨域 并设置访问权限 允许跨域携带cookie信息,使用JWT可关闭
service.defaults.withCredentials = false
service.interceptors.response.use(
// 接收到响应数据并成功后的一些共有的处理关闭loading等
response => {
const res = response.data
// 如果自定义代码不是200则将其判断为错误。
if (res.code !== 200) {
// 50008: 非法Token; 50012: 异地登录; 50014: Token失效;
if (res.code === 401 || res.code === 50012 || res.code === 50014) {
// 重新登录
MessageBox.confirm('会话失效,您可以留在当前页面,或重新登录', '权限不足', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
center: true
}).then(() => {
window.location.href = '#/login'
})
} else { // 其他异常直接提示
Message({
showClose: true,
message: '⚠' + res.message || 'Error',
type: 'error',
duration: 3 * 1000
})
}
return Promise.reject(new Error(res.message || 'Error'))
} else {
return res
}
},
error => {
/** *** 接收到异常响应的处理开始 *****/
// console.log('err' + error) // for debug
Message({
showClose: true,
message: error.message,
type: 'error',
duration: 5 * 1000
})
return Promise.reject(error)
}
)
export default service

@ -0,0 +1,58 @@
Math.easeInOutQuad = function(t, b, c, d) {
t /= d / 2
if (t < 1) {
return c / 2 * t * t + b
}
t--
return -c / 2 * (t * (t - 2) - 1) + b
}
// requestAnimationFrame for Smart Animating http://goo.gl/sx5sts
var requestAnimFrame = (function() {
return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || function(callback) { window.setTimeout(callback, 1000 / 60) }
})()
/**
* Because it's so fucking difficult to detect the scrolling element, just move them all
* @param {number} amount
*/
function move(amount) {
document.documentElement.scrollTop = amount
document.body.parentNode.scrollTop = amount
document.body.scrollTop = amount
}
function position() {
return document.documentElement.scrollTop || document.body.parentNode.scrollTop || document.body.scrollTop
}
/**
* @param {number} to
* @param {number} duration
* @param {Function} callback
*/
export function scrollTo(to, duration, callback) {
const start = position()
const change = to - start
const increment = 20
let currentTime = 0
duration = (typeof (duration) === 'undefined') ? 500 : duration
var animateScroll = function() {
// increment the time
currentTime += increment
// find the value with the quadratic in-out easing function
var val = Math.easeInOutQuad(currentTime, start, change, duration)
// move the document.body
move(val)
// do the animation unless its over
if (currentTime < duration) {
requestAnimFrame(animateScroll)
} else {
if (callback && typeof (callback) === 'function') {
// the animation is done so lets callback
callback()
}
}
}
animateScroll()
}

@ -0,0 +1,880 @@
<template>
<div class="child-star-certification">
<h1
class="form-title"
v-if="!isModelCertified"
style="margin-bottom: 30px;"
>
初次申请认证
</h1>
<h1 class="form-title" v-if="isModelCertified"></h1>
<div v-if="isModelCertified" class="star-container">
<i
v-for="star in this.form.level"
:key="star"
class="el-icon-star-on"
></i>
</div>
<div class="content-container">
<div class="form-container">
<el-steps
:active="stepFinishStatus"
finish-status="success"
simple
style="margin-bottom: 20px"
>
<el-step title="认证要求"></el-step>
<el-step title="填写表单"></el-step>
</el-steps>
<div v-if="currentStep === 1" class="step-container">
<table class="requirement-table">
<thead>
<tr>
<th>打卡课程</th>
<th>要求等级</th>
<th>是否打卡</th>
</tr>
</thead>
<tbody>
<tr v-for="(requirement, index) in ModelRequest" :key="index">
<td>{{ requirement.courseName }}</td>
<td>{{ requirement.level }}</td>
<td>
<span v-if="requirement.completed" class="completed"
>&#10003;</span
>
<span v-else class="incomplete">&#10005;</span>
</td>
</tr>
</tbody>
</table>
<el-button @click="nextStep" class="next-button">下一步</el-button>
</div>
<div v-if="currentStep === 2">
<el-form
ref="modelForm"
:model="form"
:rules="rules"
label-position="left"
label-width="100px"
>
<el-form-item label="真实姓名" prop="actualName">
<el-input
v-model="form.actualName"
placeholder="请输入真实姓名"
></el-input>
</el-form-item>
<el-form-item label="身份证号" prop="idCard">
<el-input
v-model="form.idCard"
placeholder="请输入身份证号"
></el-input>
</el-form-item>
<el-form-item label="年龄/岁" prop="age">
<el-input
v-model="form.age"
type="number"
placeholder="请输入年龄"
></el-input>
</el-form-item>
<el-form-item label="性别" prop="sex">
<el-radio-group v-model="form.sex">
<el-radio label="1"></el-radio>
<el-radio label="0"></el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="身高/cm" prop="height">
<el-input
v-model="form.height"
type="number"
placeholder="请输入身高"
></el-input>
</el-form-item>
<el-form-item label="体重/kg" prop="weight">
<el-input
v-model="form.weight"
type="number"
placeholder="请输入体重"
></el-input>
</el-form-item>
<el-form-item label="邮箱" prop="email">
<el-input v-model="form.email" type="email"></el-input>
</el-form-item>
<el-form-item label="证明视频" prop="certification">
<el-upload
class="upload-demo"
action="http://localhost:8000/upload"
:on-success="handleSuccess"
:before-upload="beforeUpload"
>
<el-button size="small" type="primary">点击上传</el-button>
</el-upload>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitForm"></el-button>
<el-button @click="resetForm"></el-button>
</el-form-item>
</el-form>
</div>
</div>
<div class="box">
<div class="donut-leg-left">
<div class="donut-feet"></div>
</div>
<div class="donut-leg-right">
<div class="donut-feet"></div>
</div>
<div class="shadow"></div>
<div class="donut-circle">
<div class="donut-circle-copy">
<div class="donut-face">
<div class="eyes"></div>
<div class="mouth"></div>
</div>
<div class="sprinkler-1"></div>
<div class="sprinkler-2"></div>
<div class="sprinkler-3"></div>
<div class="sprinkler-4"></div>
<div class="sprinkler-5"></div>
<div class="sprinkler-6"></div>
<div class="sprinkler-7"></div>
<div class="sprinkler-8"></div>
</div>
<div class="donut-hole"></div>
<div class="donut-hand-left"></div>
<div class="donut-hand-right"></div>
</div>
</div>
</div>
</div>
</template>
<script>
import { update } from "@/api/user";
import { submitModel, getModelDetail, getModelRequest } from "@/api/model";
import { mapActions } from "vuex";
export default {
data() {
return {
form: {
actualName: "",
idCard: "",
age: "",
sex: "",
height: "",
weight: "",
certification: "",
level: "",
email: "",
},
ModelRequest: [
//
],
stepFinishStatus: 0,
isModelCertified: false, //
currentStep: 1, //
rules: {
actualName: [
{ required: true, message: "请输入真实姓名", trigger: "blur" },
{
min: 2,
max: 20,
message: "长度在 2 到 20 个字符",
trigger: "change",
},
],
idCard: [
{ required: true, message: "请输入身份证号", trigger: "blur" },
{
pattern: /^\d{17}(\d|X|x)$/,
message: "请输入合法的身份证号",
trigger: "change",
},
],
age: [
{ required: true, message: "请输入年龄", trigger: "blur" },
{
type: "number",
message: "年龄必须为数字值",
trigger: "change",
validator: (rule, value, callback) => {
if (isNaN(value)) {
callback(new Error("年龄必须为数字值"));
} else {
callback();
}
},
},
],
email: [
{ required: true, message: "请输入邮箱地址", trigger: "blur" },
{
type: "email",
message: "请输入正确的邮箱地址",
trigger: ["blur", "change"],
},
],
height: [
{ required: true, message: "请输入身高", trigger: "blur" },
{
type: "number",
message: "身高必须为数字值",
trigger: "change",
validator: (rule, value, callback) => {
if (isNaN(value)) {
callback(new Error("身高必须为数字值"));
} else {
callback();
}
},
},
],
weight: [
{ required: true, message: "请输入体重", trigger: "blur" },
{
type: "number",
message: "体重必须为数字值",
trigger: "change",
validator: (rule, value, callback) => {
if (isNaN(value)) {
callback(new Error("体重必须为数字值"));
} else {
callback();
}
},
},
],
sex: [{ required: true, message: "请选择性别", trigger: "change" }],
certification: [
{
required: true,
message: "请上传证明视频",
trigger: "change",
validator: (rule, value, callback) => {
console.log(value);
if (this.form.certification == "") {
callback(new Error("请上传证明视频"));
} else {
callback();
}
},
},
],
},
};
},
beforeMount() {
getModelDetail(-1).then((res) => {
if (res.data != "" && res.data != null) {
this.form = res.data;
this.form.sex = `${res.data.sex}`;
this.form.certification = "";
this.isModelCertified = true;
}
});
getModelRequest().then((res) => {
console.log(res);
this.ModelRequest = res.data;
for (let i = 0; i < this.ModelRequest.length; i++) {
switch (this.ModelRequest[i].level) {
case 1: {
this.ModelRequest[i].level = "初级";
break;
}
case 2: {
this.ModelRequest[i].level = "中级";
break;
}
case 3: {
this.ModelRequest[i].level = "高级";
break;
}
default:
break;
}
}
console.log(this.ModelRequest);
});
},
methods: {
nextStep() {
//
const allRequirementsCompleted = this.ModelRequest.every(
(req) => req.completed
);
if (allRequirementsCompleted) {
this.stepFinishStatus = 1;
this.currentStep = 2; //
} else {
this.$message.warning("请完成所有要求再进行认证!");
}
},
submitForm() {
this.$refs.modelForm.validate((valid) => {
if (valid) {
submitModel(this.form).then((res) => {
this.$message.success("认证申请成功");
this.stepFinishStatus = 2;
});
} else {
this.$message.error("表单验证失败");
}
});
},
resetForm() {
this.$refs.modelForm.resetFields();
},
handleSuccess(file) {
this.form.certification = file.data;
console.log(this.form.certification);
if (this.form.certification != "") {
this.$message.success("视频上传成功");
}
},
beforeUpload(file) {
const isVideo = file.type.startsWith("video/");
if (!isVideo) {
this.$message.error("只能上传视频文件");
return false; //
}
return true; //
},
},
};
</script>
<style scoped>
.requirement-table {
width: 100%;
border-collapse: collapse;
margin-top: 20px;
}
.requirement-table th,
.requirement-table td {
border: 1px solid #ddd;
padding: 8px;
text-align: center;
}
.requirement-table th {
background-color: #f2f2f2;
font-weight: bold;
}
.completed {
color: green;
margin-left: 5px;
}
.incomplete {
color: red;
margin-left: 5px;
}
.next-button {
margin-top: 20px;
background-color: #409eff;
color: #fff;
}
.requirement-item {
margin-bottom: 10px;
display: flex;
align-items: center;
}
.completed {
color: green;
/* 已完成的颜色 */
margin-left: 5px;
}
.incomplete {
color: red;
/* 未完成的颜色 */
margin-left: 5px;
}
.next-button {
margin-top: 20px;
background-color: #409eff;
/* 按钮背景色 */
color: #fff;
/* 按钮文字颜色 */
}
.is-process {
width: 70px !important;
}
.star-container {
font-size: 24px;
margin-bottom: 20px;
}
.el-icon-star-on {
color: gold;
/* 星星颜色 */
}
.child-star-certification {
display: flex;
flex-direction: column;
align-items: center;
}
.form-title {
font-size: 24px;
}
.content-container {
display: flex;
}
.form-container {
width: 500px;
margin-right: 100px;
/* 调整表单与 box 之间的间距 */
border: 1px solid #ddd;
/* 添加边框样式 */
border-radius: 8px;
/* 添加边框圆角 */
padding: 20px;
/* 添加内边距 */
}
body {
background: #fceec1;
}
.box {
position: relative;
margin: auto;
margin-top: 5%;
width: 350px;
height: 350px;
border-radius: 50%;
background: #fffcf4;
}
.donut-circle {
position: absolute;
top: 25%;
left: 25%;
width: 50%;
height: 50%;
background: #fc75b9;
border-radius: 50%;
z-index: 5;
animation-name: bounce;
animation-timing-function: cubic-bezier(0.28, 0.84, 0.42, 1);
animation-duration: 3s;
animation-delay: 3s;
animation-iteration-count: infinite;
}
.donut-circle-copy {
width: 100%;
height: 100%;
position: absolute;
background: #fc75b9;
border-radius: 50%;
border-bottom: 10px solid #f1be7c;
box-shadow: #efb365 0px 2px 3px 1px;
z-index: 5;
}
@keyframes bounce {
0% {
transform: scale(1, 1) translateY(5px);
}
10% {
transform: scale(1.01, 1) translateY(10px);
}
30% {
transform: scale(1, 1) translateY(-60px);
}
50% {
transform: scale(1.05, 0.95) translateY(0);
}
57% {
transform: scale(1, 1) translateY(-7px);
}
64% {
transform: scale(1, 1) translateY(0);
}
100% {
transform: scale(1, 1) translateY(0);
}
}
.donut-hole {
position: absolute;
top: 33%;
left: 33%;
width: 34%;
height: 34%;
background: white;
border-radius: 50%;
z-index: 6;
}
.donut-face {
position: absolute;
top: 5%;
left: 35%;
width: 30%;
height: 25%;
border-radius: 50%;
}
.eyes:before,
.eyes:after {
content: "";
position: absolute;
top: 20%;
width: 8px;
height: 6px;
border-radius: 50%;
background: #6d3d1b;
transition: 0.5s;
animation: jump-eyes 3s infinite;
}
.eyes:before {
left: 10%;
}
.eyes:after {
right: 10%;
}
@keyframes jump-eyes {
0% {
height: 4px;
}
30% {
height: 4px;
}
50% {
height: 5px;
}
67% {
height: 6px;
}
100% {
height: 6px;
}
}
.mouth {
position: absolute;
top: 60%;
left: 30%;
width: 20px;
height: 3px;
background: transparent;
border-top: 0;
border-bottom: 4px solid #6d3d1b;
border-radius: 0 0 126px 126px / 0 0 90px 90px;
}
.sprinkler-1 {
position: absolute;
width: 14px;
height: 4px;
top: 20%;
left: 70%;
transform: rotate(140deg);
background: #7fd4fa;
border-radius: 50px;
}
.sprinkler-2 {
position: absolute;
width: 14px;
height: 4px;
top: 35%;
left: 80%;
transform: rotate(180deg);
background: #f8cd54;
border-radius: 50px;
}
.sprinkler-3 {
position: absolute;
width: 14px;
height: 4px;
top: 60%;
left: 75%;
transform: rotate(160deg);
background: #b8e986;
border-radius: 50px;
}
.sprinkler-4 {
position: absolute;
width: 14px;
height: 4px;
top: 80%;
left: 65%;
transform: rotate(240deg);
background: #f8cd54;
border-radius: 50px;
}
.sprinkler-5 {
position: absolute;
width: 14px;
height: 4px;
top: 80%;
left: 40%;
transform: rotate(30deg);
background: #7fd4fa;
border-radius: 50px;
}
.sprinkler-6 {
position: absolute;
width: 14px;
height: 4px;
top: 70%;
left: 20%;
transform: rotate(100deg);
background: #b8e986;
border-radius: 50px;
}
.sprinkler-7 {
position: absolute;
width: 14px;
height: 4px;
top: 50%;
left: 10%;
transform: rotate(10deg);
background: #7fd4fa;
border-radius: 50px;
}
.sprinkler-8 {
position: absolute;
width: 14px;
height: 4px;
top: 25%;
left: 20%;
transform: rotate(160deg);
background: #f8cd54;
border-radius: 50px;
}
.donut-hand-left {
position: absolute;
left: -20%;
top: 50%;
width: 25%;
height: 7%;
border-top-right-radius: 40%;
border-bottom-right-radius: 40%;
transform: rotate(140deg);
background: #f8daae;
z-index: 4;
animation: hand-jump 3s infinite;
animation-delay: 3s;
}
@keyframes hand-jump {
0% {
transform: rotate(140deg);
}
10% {
transform: rotate(140deg);
}
30% {
transform: rotate(160deg);
}
50% {
transform: rotate(140deg);
}
57% {
transform: rotate(140deg);
}
64% {
transform: rotate(140deg);
}
100% {
transform: rotate(140deg);
}
}
.donut-hand-right {
position: absolute;
right: -20%;
top: 50%;
width: 25%;
height: 7%;
border-top-left-radius: 40%;
border-bottom-left-radius: 40%;
transform: rotate(220deg);
background: #f8daae;
z-index: 4;
animation: hand-jump-right 3s infinite;
animation-delay: 3s;
}
@keyframes hand-jump-right {
0% {
transform: rotate(220deg);
}
10% {
transform: rotate(220deg);
}
30% {
transform: rotate(200deg);
}
50% {
transform: rotate(220deg);
}
57% {
transform: rotate(220deg);
}
64% {
transform: rotate(220deg);
}
100% {
transform: rotate(220deg);
}
}
.donut-leg-left {
position: absolute;
bottom: 15%;
left: 40%;
width: 3%;
height: 32%;
background: #eebb78;
z-index: 1;
animation: bounce-leg 3s infinite;
animation-delay: 3s;
}
.donut-leg-right {
position: absolute;
bottom: 15%;
right: 40%;
width: 3%;
height: 32%;
background: #eebb78;
z-index: 1;
animation: bounce-leg 3s infinite;
animation-delay: 3s;
}
@keyframes bounce-leg {
0% {
transform: scale(1, 1) translateY(0);
}
10% {
transform: scale(1, 1) translateY(0);
}
30% {
transform: scale(1, 1) translateY(-30px);
}
50% {
transform: scale(1.05, 0.95) translateY(0);
}
57% {
transform: scale(1, 1) translateY(-7px);
}
64% {
transform: scale(1, 1) translateY(0);
}
100% {
transform: scale(1, 1) translateY(0);
}
}
.donut-feet {
position: absolute;
bottom: 0%;
left: -4px;
width: 18px;
height: 12%;
background: #8c6028;
border-top-left-radius: 50px;
border-top-right-radius: 50px;
border-bottom-left-radius: 20px;
border-bottom-right-radius: 20px;
}
.shadow {
position: absolute;
left: 35%;
bottom: 12%;
width: 30%;
height: 6%;
background: #dad8d3;
border-radius: 50%;
z-index: 0;
animation: shadow-scale 3s infinite;
animation-delay: 3s;
}
@keyframes shadow-scale {
0% {
transform: scale(1, 1);
opacity: 1;
}
30% {
transform: scale(1.3, 1.2);
opacity: 0.6;
}
50% {
transform: scale(1, 1);
opacity: 1;
}
}
</style>

@ -0,0 +1,662 @@
<template>
<div class='coursemain'>
<div class="course-main">
<section class="search-container">
<div class="search-item">
<div class="title-name">课程方向</div>
<div class="all-items">
<el-tag
class="category-poniter"
effect="plain"
type="info"
@click='buildingCondition("allDirection",0)'
>全部</el-tag>
<el-tag
v-for='item in courseDirections'
:key='item.id'
:class="queryCourseParams.entity.courseDirection == item.id ? 'category-poniter' : 'category-poniter-item'"
effect="plain"
type="info"
@click='buildingCondition("fcategory",item.id)'
>
{{ item.name }}
</el-tag>
</div>
</div>
<div class="search-item" style="top: 45px;">
<div class="title-name">课程分类</div>
<div class="all-items">
<el-tag
class="category-poniter"
effect="plain"
type="info"
@click='buildingCondition("allCategory",0)'
>全部</el-tag>
<el-tag
v-for='item in courseCategorys'
:key='item.id'
:class="queryCourseParams.entity.courseCategory == item.id ? 'category-poniter' : 'category-poniter-item'"
effect="plain"
type="info"
@click='buildingCondition("scategory",item.id)'
> {{ item.name }}
</el-tag>
</div>
</div>
<div class="search-item" style="top: 90px;">
<div class="title-name">课程难度</div>
<div class="all-items">
<el-tag
class="category-poniter"
effect="plain"
type="info"
@click='buildingCondition("allLevel",0)'
>全部</el-tag>
<el-tag
v-for='item in courseLevel'
:key='item.code'
:class="queryCourseParams.entity.courseLevel == item.code ? 'category-poniter' : 'category-poniter-item'"
effect="plain"
type="info"
@click='buildingCondition("clevel",item.code)'
> {{ item.text }}
</el-tag>
</div>
</div>
</section>
</div>
<div class='main-container'>
<div class="container-top">
<ul class="all">
<li
class="item"
@click="handleZonghe"
:style='queryCourseParams.entity.sortBy==0 ? "color:#2C80FF" :""'
>综合</li>
<li class="item split">|</li>
<li
class="item"
@click="handleNewCourse"
:style='queryCourseParams.entity.sortBy==1 ? "color:#2C80FF" :""'
>最新课程</li>
<li class="item split">|</li>
<li
class="item"
@click="mostbuy"
:style='queryCourseParams.entity.sortBy==2 ? "color:#2C80FF" :""'
>最多购买 </li>
<!-- <li class="item split">|</li>
<li
class="item-price"
@click="handlePrice"
>
<span :style='priceSortBy=="4" || priceSortBy=="5" ? "color:#2C80FF" :""'>价格</span>
<span class="arrow">
<el-icon :style='priceSortBy=="4" ? "color:#2C80FF" :""'><caret-top /></el-icon>
<el-icon :style='priceSortBy=="5" ? "color:#2C80FF" :""'><caret-bottom /></el-icon>
</span>
</li> -->
</ul>
<ul class="right">
<li class="right-item">
<el-radio-group v-model="radio">
<el-radio label="1">免费课程</el-radio>
<el-radio label="2">会员课程</el-radio>
</el-radio-group>
</li>
</ul>
</div>
<!-- 课程展示部分 -->
<div class="container-body">
<div class="newCourseContent">
<ul class="courseUl">
<li
class='courseItem'
v-for='item in queryCourse.courseList'
:key='item.id'
>
<meta name="referrer" content="no-referrer" />
<router-link :to="{ path: '/course/' + item.id }">
<div class='courseInfo'>
<div class='courseBg'>
<img :src="item.courseImage" >
</div>
<div class="courseName">{{item.courseName}}</div>
<div class="courseDegree"> {{courseType[item.courseLevel]}} · {{item.studyPerson}}人报名</div>
<div class="coursePriceZero" v-if="item.isFree == 1">
<div class="pricefree">免费学习 </div>
<img src="../assets/image/free.png" alt="">
</div>
<div class="coursePrice" v-else-if="item.isFree == 0">
<div class="courseMemberbg"><span class="courseMember">会员免费 </span></div>
<div class="price"> ¥ 0.01</div>
</div>
</div>
</router-link>
</li>
</ul>
</div>
<!-- 分页 -->
<div class='pages'>
<el-pagination
background
layout="prev, pager, next"
:page-size="queryCourseParams.pageSize"
:total= "queryCourse.total"
@current-change="handleCurrentChange"
/>
</div>
</div>
</div>
</div>
</template>
<script>
import { getCourseDirection, getCourseCategory, searchCourse } from '../api/courseManage';
export default {
data() {
return {
//
queryCourse:{
//
courseList:[],
//
total:0,
},
courseType:['','初级','中级','高级'],
courseDirections: [],
courseCategorys: [],
courseLevel: [
{ text: '初级', code: '1' },
{ text: '中级', code: '2' },
{ text: '高级', code: '3' },
],
courseList: [],
total: 0,
queryCourseParams: {
pageNum: 1,
pageSize: 8,
entity: {
//
courseDirection: 0,
//
courseCategory: 0,
//
courseLevel: 0,
//
isFree: 3,
sortBy: 0,
},
},
radio:'',
currentType: {
fcategory: { id: '' },
scategory: { id: '' },
clevel: { id: '' },
},
priceSortBy: '1',
};
},
methods: {
//
querySearchCourse() {
searchCourse(this.queryCourseParams.pageNum, this.queryCourseParams.pageSize,this.queryCourseParams.entity)
.then((res) => {
this.queryCourse.courseList = res.data.records || [];
this.queryCourse.total = res.data.total;
})
.catch((error) => {
//
console.error('Error fetching course data:', error);
});
},
//
getSecondCategorysFn(params) {
getSecondCategorys(params).then(res => {
this.secondCategorys = res.data.list;
});
},
//
handleCurrentChange(val) {
this.queryCourseParams.pageNum = val;
this.querySearchCourse();
},
//
handleZonghe() {
this.queryCourseParams.entity.sortBy = 0;
this.radio='';
this.queryCourseParams.entity.isFree=3;
this.querySearchCourse();
},
//
handleNewCourse() {
this.queryCourseParams.entity.sortBy = 1;
this.querySearchCourse();
},
//
mostbuy() {
this.queryCourseParams.entity.sortBy = 2;
this.querySearchCourse();
},
//
// handlePrice() {
// if (this.priceSortBy === '4' || this.priceSortBy !== '5') {
// this.priceSortBy = '5';
// this.queryCourseParams.entity.sortBy = 'price-desc';
// } else if (this.priceSortBy === '5') {
// this.priceSortBy = '4';
// this.queryCourseParams.entity.sortBy = 'price-asc';
// }
// this.querySearchCourse();
// },
//
buildingCondition(type, id) {
//
if (type === 'fcategory') {
//
this.queryCourseParams.entity.isFree = 3;
this.radio = '0';
//class
this.queryCourseParams.entity.courseDirection=id;
// this.currentType['scategory'].id = '';
this.queryCourseParams.entity.courseLevel=0;
//
// this.queryCourseParams.entity.secondCategory = '';
// this.queryCourseParams.entity.courseLevel = '';
// this.secondCategorysParams.categoryId = id;
// this.getSecondCategorysFn(this.secondCategorysParams);
//
this.querySearchCourse();
return;
}
//
if (type === 'scategory') {
this.queryCourseParams.entity.isFree = 3;
this.radio = '0';
this.queryCourseParams.entity.courseCategory= id;
this.queryCourseParams.entity.courseLevel = 0;
//
this.querySearchCourse();
return;
}
//
if (type === 'clevel') {
this.queryCourseParams.entity.courseLevel = id;
this.querySearchCourse();
return;
}
//
if(type==='allDirection'){
this.queryCourseParams.entity.courseDirection = 0;
this.querySearchCourse();
return;
}
//
if(type==='allCategory'){
this.queryCourseParams.entity.courseCategory = 0;
this.querySearchCourse();
return;
}
//
if(type==='allLevel'){
this.queryCourseParams.entity.courseLevel = 0;
this.querySearchCourse();
return;
}
},
},
beforeMount() {
getCourseDirection().then(res => {
this.courseDirections = res.data;
});
getCourseCategory().then(res=>{
this.courseCategorys=res.data;
})
// this.getSecondCategorysFn(this.secondCategorysParams);
this.querySearchCourse();
},
//
watch:{
radio(newValue){
//
if( newValue == '1' ){
this.queryCourseParams.entity.isFree = 1;
}else if( newValue =='2' ){//
this.queryCourseParams.entity.isFree = '0';
}
this.querySearchCourse();
}
}
}
</script>
<style scoped>
.course-main {
width: 100%;
height: 140px;
background: #f3f5f9;
}
.search-container{
width: 100%;
margin: 0 auto;
position: relative;
height: 100%;
}
.search-item{
display: flex;
overflow: hidden;
cursor: pointer;
position: absolute;
height: 45px;
transition: all 0.5s;
}
.search-item-transition:hover{
z-index: 777;
height: auto;
box-shadow: rgb(95 101 105 / 10%) 0px 12px 20px 0px;
border-radius: 8px;
background: rgba(255,255,255);
}
.search-item .title-name {
width: 100px;
font-size: 15px;
font-family: Microsoft YaHei;
font-weight: bold;
line-height: 25px;
text-align: justify;
color: #333333;
padding: 10px;
opacity: 1;
}
.search-item .title-name:after {
content: '.';
width: 100%;
display: inline-block;
overflow: hidden;
height: 0;
}
.search-item .all-items{
min-height: 25px;
display: flex;
flex-wrap: wrap;
}
.title .all-list {
width: 40px;
height: 25px;
line-height: 25px;
border-radius: 4px;
padding: 0 10px;
align-items: center;
text-align: center;
}
.title .all {
opacity: 1;
color: #2c80ff;
}
.title .item {
height: 25px;
line-height: 25px;
margin: 0 15px;
font-size: 16px;
font-family: Microsoft YaHei;
font-weight: 400;
line-height: 21px;
opacity: 1;
}
.title .item .active {
color: #2c80ff;
}
.category-poniter {
height: 25px;
line-height: 25px;
margin: 10px 5px;
cursor: pointer;
border: none;
background: rgba(44, 128, 255, 0.1);
color: #2c80ff;
}
.category-poniter-item {
height: 25px;
line-height: 25px;
margin: 10px 5px;
cursor: pointer;
border: none;
background: none;
color: rgba(81, 87, 89, 1);
}
/* 视频区域 */
.main-container {
width: 100%;
margin: 0 auto;
border-top: solid 1px pink;
}
.container-top {
display: flex;
justify-content: space-between;
align-items: center;
}
.all {
display: flex;
padding-top: 20px;
font-size: 16px;
color: #515759;
}
.all .item:first-child {
margin-right: 20px;
}
.all .item {
margin: 0 10px;
cursor: pointer;
}
.right {
display: flex;
padding-top: 20px;
font-size: 16px;
color: #515759;
}
.right .right-item {
margin-left: 10px;
}
.right .right-items {
margin-right: 0px;
}
.arrow {
position: relative;
}
.arrow i:first-child {
position: absolute;
top: -1px;
}
.arrow i:last-child {
position: absolute;
top: 7px;
}
.check {
width: 15px;
height: 15px;
cursor: pointer;
}
.up {
position: absolute;
top: 5px;
left: 2px;
}
.down {
position: absolute;
top: 15px;
left: 2px;
transform: rotate(180deg);
-ms-transform: rotate(180deg); /* IE 9 */
-moz-transform: rotate(180deg); /* Firefox */
-webkit-transform: rotate(180deg); /* Safari 和 Chrome */
-o-transform: rotate(180deg); /* Opera */
}
.newCourseContent {
width: 1200px;
margin: 30px auto 0px auto;
}
.newCourseContent .courseUl {
display: flex;
flex-wrap: wrap;
}
.courseItem{
width: 285px;
height: 280px;
margin: 0 20px 20px 0;
transition: margin-top 0.2s;
}
.courseItem a{
text-decoration: none;
}
.courseItem:hover{
margin-top: -10px;
cursor: pointer;
}
.courseItem:nth-child(4n+0){
margin-right: 0 !important;
}
.courseInfo{
position: relative;
width: 100%;
height: 270px;
background: #ffffff;
box-shadow: 1px 1px 10px rgb(27 39 94 / 40%);
opacity: 1;
border-bottom-left-radius: 6px;
border-bottom-right-radius: 6px;
overflow: hidden;
text-decoration: none;
}
.courseBg{
position: relative;
width: 100%;
height: 160px;
}
.courseBg img{
width: 100%;
height: 100%;
}
.courseName{
margin: 10px;
font-weight: bold;
font-size: 14px;
color: #333333;
display: -webkit-box;
overflow: hidden;
}
.courseDegree{
margin-left: 10px;
font-size: 12px;
color: #808080;
}
/* 课程会员价钱 */
.coursePrice {
display: flex;
justify-content: space-around;
align-items: center;
width: 140px;
font-size: 14px;
margin-top: 10px;
padding: 0 5px;
}
.coursePricePri{
width: 75px;
font-size: 14px;
margin-top: 18px;
padding: 0 13px;
color: rgba(255, 114, 127, 1);
font-weight: 700;
}
/* 免费课程 */
.coursePriceZero{
display: flex;
justify-content: space-between;
align-items: center;
width: 90px;
font-size: 14px;
margin-top: 10px;
padding: 0 10px;
color: rgba(53, 134, 255, 1);
}
.courseMemberbg {
position: relative;
width: 80px;
height: 20px;
color: #ffffff;
background: linear-gradient(90deg, #ff928e 0%, #fe7062 99%);
border-radius: 24px 0px 24px 0px;
}
.courseMember {
position: absolute;
line-height: 20px;
left: 13px;
font-weight: 700;
}
/* 课程价格 */
.price {
line-height: 25px;
left: 100px;
color: #ff727f;
font-weight: 700;
}
.pages{
display: flex;
align-items: center;
justify-content: center;
padding:20px 0;
}
</style>

@ -0,0 +1,530 @@
<template>
<div class="courseContainer">
<div class="courseInfoTop">
<div class="info-container">
<ul class="route">
<li class="route-item" style="cursor: pointer">
<router-link to="/course" style="color: #fff">课程</router-link>
</li>
<li class="route-item">></li>
<li class="route-item" style="cursor: pointer">
{{ courseInfo.isFree == 1 ? '免费课' : '会员课' }}
</li>
<li class="route-item">></li>
<li class="route-item">{{ courseInfo.courseName }}</li>
</ul>
<div class="name">{{ courseInfo.courseName }}</div>
<div class="info">
<div class="Avat">
<img src="../assets/image/Avat62.png" alt="" />
</div>
<ul class="teacherName">
<li class="name-item">
{{ courseInfo.courseName }}
<img src="../assets/image/teacherStart.png" alt="" />
</li>
<li class="name-item">金牌讲师</li>
</ul>
<ul class="access">
<li class="access-item">难度 : </li>
<li class="access-item">{{ courseType[courseInfo.courseLevel] }}</li>
<li class="access-item">·</li>
<li class="access-item">时长 : </li>
<li class="access-item">{{ courseInfo.courseTime }}个小时</li>
<li class="access-item">·</li>
<li class="access-item">学习人数 : </li>
<li class="access-item">{{ courseInfo.studyPerson }}</li>
<li class="access-item">·</li>
<li class="access-item">综合评分 : </li>
<li class="access-item">10.00</li>
<el-link @click="clock_in" type="primary" :underline="false" style="margin-left: 330px; font-size: 18px;">打卡课程</el-link> </ul>
</div>
</div>
</div>
<div class="info-nav">
<div class="nav-container">
<div class="chapter-item" @click='active = true'>
<div :class="active ? 'active1' : ''">章节</div>
<div class="line" :class='active ? "active2" : ""'></div>
</div>
<div class="chapter-item" @click='active = false'>
<div :class="!active ? 'active1' : ''">下载资料</div>
<div class="line" :class='!active ? "active2" : ""'></div>
</div>
</div>
</div>
<div class="course" v-if='active'>
<div class="main">
<div class="introduction">
<div class="desc">
{{ courseInfo.courseDetail }}
</div>
<div class="btn">
<button class="btn-item active">成为会员</button>
</div>
</div>
<div class="video" v-for="item in courseVideos" :key="item.id">
<div class="chapterName">{{ item.name }}</div>
<div class="chapterDesc">{{ item.detail }}</div>
<ul class="videos">
<li class="video-item">
<div class="video-itemIcon">
<i class="el-icon-video-camera"></i>
</div>
<div class="item-name">
<span class="shipin">视频</span>
</div>
<button class="btn-learn" @click='goPlay(item.id)'>开始学习</button>
<div class="clearfloat"></div>
</li>
</ul>
</div>
</div>
</div>
<div v-else>
<div v-if='attachments.length > 0'>
<div class="down" v-for='item in attachments' :key='item.id'>
<div class="source">
<span class="downloadCourse">{{ item.attachmentName }}</span>
<button class="downloadbtn" @click="downloadSource(item)"></button>
</div>
</div>
</div>
<div v-else>
<el-empty description="该课程暂无资料"></el-empty>
</div>
</div>
</div>
</template>
<script>
import { getCourseDetail, clockIn, courseCheckAuth } from '../api/courseManage';
import {getInfo} from '../api/user'
import { mapGetters } from 'vuex'
export default {
data() {
return {
courseType: ['', '初级', '中级', '高级'],
courseId: this.$route.params.id,
active: true,
attachments: [],
courseVideos: {},
courseInfo: {},
};
},
mounted() {
// $route.params
//const courseId = this.$route.params.id;
},
computed: {
...mapGetters([
'token'
])
},
beforeMount() {
getCourseDetail(this.courseId).then((res) => {
this.courseInfo = res.data;
if (this.courseInfo.isFree == 1) {
this.courseVideos = res.data.courseVideoList;
}
else {
courseCheckAuth().then(res => {
console.log(res)
if (res.data == 1) {
this.courseVideos = res.data.courseVideoList;
}
else {
this.$message({
type: 'warning',
message: '请先成为会员!'
});
}
})
}
// this.attachments = res.data.data.bizCourseAttachments;
// this.courseChapters = res.data.data.bizCourseChapters;
});
},
methods: {
downloadSource(item) {
// const router = useRouter();
// const ElMessage = this.$message;
// if (!this.useUserStore().token) {
// ElMessage.info({
// message: '',
// });
// router.push('/login');
// return;
},
// courseCheckAuth:({
// // courseId: item.courseId,
// console.log(1)
// }).then((res) => {
// if (!res.data.data.hasAuth) {
// ElMessage.info({
// message: '',
// });
// return;
// }
// downloadAttachment({
// courseId: item.courseId,
// attachmentId: item.id,
// }).then((res) => {
// const blob = new Blob([res]);
// let fileName = item.attachmentName;
// let fileUrl = item.attachmentUrl;
// const extName = fileUrl.substring(fileUrl.lastIndexOf('.'));
// fileName = fileName + extName;
// const link = document.createElement('a');
// link.download = fileName;
// link.target = '_blank';
// link.style.display = 'none';
// link.href = URL.createObjectURL(blob);
// document.body.appendChild(link);
// link.click();
// URL.revokeObjectURL(link.href);
// document.body.removeChild(link);
// });
// })
// },
//
clock_in(){
clockIn(this.courseId).then(res=>{
if(res.data==1)
this.$message.success(res.message);
else
this.$message.error(res.message);
})
},
goPlay(videoId) {
// const router = useRouter();
const ElMessage = this.$message;
if (this.token == null || this.token == '') {
ElMessage.info({
message: '请先登录',
});
this.$router.push('/login');
return;
}
else {
this.$router.push({
path: '/courseStudy/' + this.courseId + '/' + videoId,
});
return;
}
},
}
}
</script>
<style scoped>
.courseContainer {
width: 100%;
height: 100%;
background: #f8fafc;
overflow: hidden;
}
.main {
margin: 40px auto;
width: 1200px;
height: 100%;
}
.courseInfoTop {
width: 100%;
height: 200px;
background-image: url("../assets/image/courseInfobg1920.png");
}
.nav-container {
width: 1200px;
margin: 0 auto;
color: #333333;
display: flex;
}
/* .chapter-item .active{
color: #388FFF;
} */
/* 背景部分开始 */
.courseInfoTop .info-container {
margin: 0 auto;
width: 1200px;
height: 200px;
color: #ffffff;
z-index: 5;
}
.route {
/*margin-left: 50px;*/
padding-top: 20px;
display: flex;
font-size: 14px;
}
.route .route-item {
margin-right: 10px;
}
.name {
margin: 30px 0 10px 0px;
font-size: 24px;
}
.info {
display: flex;
/*margin-left: 50px;*/
}
.info .Avat {
width: 60px;
height: 60px;
border-radius: 50%;
}
.info .Avat img {
width: 100%;
height: 100%;
border-radius: 50%;
}
.teacherName {
margin: 8px 0 0 8px;
}
.name-item img {
width: 14px;
height: 14px;
}
.access {
margin: 0 0 0 100px;
display: flex;
}
.access .access-item {
margin-right: 10px;
line-height: 60px;
}
/* 背景部分结束 */
/* 导航栏开始 */
.info-nav {
width: 100%;
background: #ffffff;
box-shadow: 0px 3px 6px rgba(0, 0, 0, 0.16);
}
.course {
margin: 0 auto;
width: 1200px;
}
.chapter {
display: flex;
font-weight: 600;
color: #333333;
margin-left: 50px;
font-size: 20px;
}
.chapter-item {
padding-bottom: 8px;
font-size: 20px;
font-weight: bold;
line-height: 80px;
margin-right: 70px;
cursor: pointer;
position: relative;
}
.chapter-item .active1 {
color: #388fff;
}
.chapter-item .active2 {
position: absolute;
width: 70%;
top: 63px;
left: calc(30% / 2);
height: 4px;
background: #388fff;
border-radius: 2px;
}
/* 导航栏结束 */
/* 课程介绍开始 */
.introduction {
/*margin-left: 50px;*/
/*padding: 20px;*/
width: 1210px;
background: #ffffff;
border-radius: 8px;
overflow: hidden;
box-shadow: 0px 3px 6px rgba(0, 0, 0, 0.09);
}
.desc {
padding: 20px;
color: #474747;
line-height: 35px;
}
.btn {
float: right;
margin-top: 10px;
padding: 0 20px 20px;
}
.btn-item {
width: 120px;
height: 40px;
/*margin: 0 20px 0 0;*/
padding: 0px;
border: 0px;
outline: none;
color: #f11d1d;
border-radius: 23px;
cursor: pointer;
}
.btn .active {
background: #f11d1d !important;
color: #ffffff;
margin-right: 10px;
}
/* 课程介绍结束 */
/* 视频目录开始 */
.video {
margin: 20px 0;
padding: 20px;
width: 1210px;
background: #ffffff;
border-radius: 8px;
overflow: hidden;
box-shadow: 0px 3px 6px rgba(0, 0, 0, 0.09);
}
.video .chapterName {
font-weight: bold;
font-size: 20px;
color: #333333;
}
.video .free {
padding-left: 20px;
font-size: 14px;
color: #388fff;
}
.chapterDesc {
margin: 10px 0;
font-size: 13px;
color: #5c5c5c;
}
.video-item {
height: 40px;
line-height: 40px;
padding: 5px 0;
/*margin: 0 0 10px 0;*/
border-radius: 8px;
}
.video-item .shipin {
color: #333333;
font-weight: bold;
}
.video-item .chapterName {
font-size: 16px;
font-weight: 400;
color: #333333;
}
.video-itemIcon,
.item-name {
float: left;
padding-left: 10px;
}
.btn-learn {
margin: 5px 5px 0 0;
float: right;
right: -100px;
width: 80px;
height: 30px;
line-height: 30px;
border: 0px;
outline: none;
color: #fff;
background: #388fff;
border-radius: 12px;
cursor: pointer;
}
.clearfloat {
clear: both;
}
/* 视频目录结束 */
.source {
margin: 2px 0;
padding: 5px;
display: flex;
justify-content: space-between;
box-shadow: 0px 3px 6px rgba(0, 0, 0, 0.09);
}
.down {
margin: 10px auto !important;
width: 1200px;
height: 100%;
padding: 5px;
background: #ffffff;
box-sizing: border-box;
border-radius: 8px;
}
.down:first-child {
margin: 40px 0 5px 0;
}
.downloadbtn {
width: 100px;
height: 30px;
line-height: 30px;
background: #388fff;
border: none;
border-radius: 8px;
color: #fff;
font-size: 14px;
cursor: pointer;
}
</style>

@ -0,0 +1,72 @@
<template>
<div class="course-study">
<h1>{{ courseVideos.name }}</h1>
<div class="video-container">
<iframe class="bilibili-video" :src="'//player.bilibili.com/player.html?bvid=' + courseVideos.bvdid" scrolling="no" border="0" frameborder="no" framespacing="0" allowfullscreen="true"></iframe> </div>
</div>
</template>
<script>
import {getVideoDetail} from '../api/courseManage'
export default {
data(){
return{
courseId:this.$route.params.courseId,
videoId:this.$route.params.itemId,
courseVideos:{}
}
},
mounted(){
getVideoDetail(this.courseId,this.videoId).then((res) => {
this.courseVideos=res.data;
});
},
};
</script>
<style scoped>
h1{
width: 300px;
height: 200px;
position: absolute;
left: 50%;
margin-left: -150px;
background-image: -webkit-linear-gradient(left,blue,#66ffff 10%,#cc00ff 20%,#CC00CC 30%, #CCCCFF 40%, #00FFFF 50%,#CCCCFF 60%,#CC00CC 70%,#CC00FF 80%,#66FFFF 90%,blue 100%);
-webkit-text-fill-color: transparent;
-webkit-background-clip: text;
-webkit-background-size: 200% 100%;
-webkit-animation: masked-animation 4s linear infinite;
font-size: 35px;
}
.course-study {
max-width: 1340px; /* 设置最大宽度为div的宽度 */
margin: 0 auto;
padding: 20px;
text-align: center;
}
.video-container {
margin-top: 70px;
box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.1);
overflow: hidden;
width: 100%; /* 宽度占满父容器 */
position: relative;
padding-bottom: 42.91%; /* 设置为16:9的宽高比例 */
}
.bilibili-video {
width: 100%;
height: 100%; /* 100% 的高度 */
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
margin: auto;
}
</style>

@ -0,0 +1,42 @@
<template>
<div>
<div class="box">🔔 {{ billboard.content }}</div>
<div class="columns">
<div class="column is-three-quarters">
<TopicList></TopicList>
</div>
<div class="column">
<CardBar></CardBar>
</div>
</div>
</div>
</template>
<script>
import { getBillboard } from "@/api/billboard";
import CardBar from "@/views/card/CardBar"
import PostList from '@/views/post/Index'
export default {
name: "Home",
components: {CardBar, TopicList: PostList},
data() {
return {
billboard: {
content: "",
},
};
},
created() {
this.fetchBillboard();
},
methods: {
async fetchBillboard() {
getBillboard().then((value) => {
const { data } = value;
this.billboard = data;
});
},
},
};
</script>

@ -0,0 +1,85 @@
<template>
<div class="membership-page">
<h1 class="page-title">会员认证</h1>
<!-- 会员认证表单 -->
<form @submit.prevent="submitMembershipForm" class="membership-form">
<!-- 你的会员认证表单字段 -->
<button type="submit" class="submit-button">提交认证</button>
</form>
<hr class="divider">
<h2 class="page-title">支付</h2>
<!-- 使用支付图片触发支付逻辑 -->
<img src="../assets/image/payment.jpg" alt="Payment QR Code" @click="submitPayment" class="payment-image">
</div>
</template>
<script>
export default {
data() {
return {
//
membershipFormData: {
// ...
},
};
},
methods: {
submitMembershipForm() {
//
// 使 this.membershipFormData
},
submitPayment() {
//
alert('支付逻辑:打开支付页面或者其他支付方式');
//
// window.location.href = 'your_payment_page_url';
},
},
};
</script>
<style scoped>
.membership-page {
text-align: center;
padding: 20px;
}
.page-title {
font-size: 24px;
margin-bottom: 20px;
}
.membership-form {
display: inline-block;
}
.submit-button {
background-color: #409EFF;
color: #fff;
border: none;
padding: 10px 20px;
font-size: 16px;
cursor: pointer;
}
.divider {
margin: 40px 0;
border-top: 1px solid #ccc;
}
.payment-image {
width: 200px;
height: 200px;
cursor: pointer;
transition: transform 0.3s ease-in-out;
}
.payment-image:hover {
transform: scale(1.1);
}
</style>

@ -0,0 +1,104 @@
<template>
<div>
<el-card shadow="never">
<div slot="header" class="clearfix">
检索到 <code>{{ list.length }}</code>
条关于 <code class="has-text-info">{{ query.keyword }}</code> 的记录
</div>
<div>
<article v-for="(item, index) in list" :key="index" class="media">
<div class="media-left">
<figure class="image is-48x48">
<img :src=item.avatar>
</figure>
</div>
<div class="media-content">
<div class="">
<p class="ellipsis is-ellipsis-1">
<el-tooltip class="item" effect="dark" :content="item.title" placement="top">
<router-link :to="{name:'post-detail',params:{id:item.id}}">
<span class="is-size-6">{{ item.title }}</span>
</router-link>
</el-tooltip>
</p>
</div>
<nav class="level has-text-grey is-mobile is-size-7 mt-2">
<div class="level-left">
<div class="level-left">
<router-link class="level-item" :to="{ path: `/member/${item.username}/home` }">
{{ item.alias }}
</router-link>
<span class="mr-1">
发布于:{{ dayjs(item.createTime).format("YYYY/MM/DD") }}
</span>
<span
v-for="(tag, index) in item.tags"
:key="index"
class="tag is-hidden-mobile is-success is-light mr-1"
>
<router-link :to="{ name: 'tag', params: { name: tag.name } }">
{{ "#" + tag.name }}
</router-link>
</span>
<span class="is-hidden-mobile">浏览:{{ item.view }}</span>
</div>
</div>
</nav>
</div>
<div class="media-right" />
</article>
</div>
<!--分页-->
<pagination
v-show="query.total > 0"
:total="query.total"
:page.sync="query.pageNum"
:limit.sync="query.pageSize"
@pagination="fetchList"
/>
</el-card>
</div>
</template>
<script>
import { searchByKeyword } from '@/api/search'
import Pagination from '@/components/Pagination'
export default {
name: 'Search',
components: { Pagination },
data() {
return {
list: [],
query: {
keyword: this.$route.query.key,
pageNum: 1,
pageSize: 10,
total: 0
}
}
},
created() {
this.fetchList()
},
methods: {
fetchList() {
searchByKeyword(this.query).then(value => {
const { data } = value
this.list = data.records
this.query.total = data.total
this.query.pageSize = data.size
this.query.pageNum = data.current
})
}
}
}
</script>
<style scoped>
</style>

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save