├── public ├── favicon.ico └── index.html ├── src ├── assets │ ├── f1.jpg │ ├── f2.jpg │ ├── f3.jpg │ ├── film1.jpg │ ├── logo.png │ ├── mesh.png │ ├── mesh2.png │ ├── title.jpg │ ├── user.png │ ├── vlogo.png │ ├── film2.webp │ ├── film3.webp │ ├── film4.webp │ ├── slider1.jpg │ ├── slider2.jpg │ ├── lazyLoading.png │ ├── icons8-loading-30.png │ └── loader-circle-regular-24.png ├── components │ ├── ErrorComponent.vue │ ├── LoadingComponent.vue │ ├── DetailTop.vue │ ├── ThirdSwiper.vue │ ├── TestGame.vue │ ├── HelloWorld.vue │ ├── SecondSwiper.vue │ ├── SwiperSvg.vue │ ├── SwiperWord.vue │ ├── ForumAdd.vue │ ├── FooterView.vue │ ├── FilmItem.vue │ ├── HeaderNav.vue │ ├── ForumDetail.vue │ ├── ThirdSwiperFirst.vue │ ├── FirstSwiper.vue │ └── ThirdSwiperSecond.vue ├── layout │ ├── LayoutContent.vue │ └── LayOut.vue ├── utils │ ├── lazyLoadView.js │ └── aes.js ├── pages │ ├── HomePage.vue │ ├── DetailPage.vue │ ├── DetailSearch.vue │ ├── UserLogin.vue │ ├── MyProfile.vue │ ├── ForumPage.vue │ └── RankingList.vue ├── main.js ├── App.vue ├── api │ ├── request.js │ └── index.js ├── router │ ├── routes.js │ └── index.js └── store │ └── index.js ├── babel.config.js ├── .gitignore ├── jsconfig.json ├── vue.config.js ├── README.md └── package.json /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/John-rong/Vmovie/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /src/assets/f1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/John-rong/Vmovie/HEAD/src/assets/f1.jpg -------------------------------------------------------------------------------- /src/assets/f2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/John-rong/Vmovie/HEAD/src/assets/f2.jpg -------------------------------------------------------------------------------- /src/assets/f3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/John-rong/Vmovie/HEAD/src/assets/f3.jpg -------------------------------------------------------------------------------- /src/assets/film1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/John-rong/Vmovie/HEAD/src/assets/film1.jpg -------------------------------------------------------------------------------- /src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/John-rong/Vmovie/HEAD/src/assets/logo.png -------------------------------------------------------------------------------- /src/assets/mesh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/John-rong/Vmovie/HEAD/src/assets/mesh.png -------------------------------------------------------------------------------- /src/assets/mesh2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/John-rong/Vmovie/HEAD/src/assets/mesh2.png -------------------------------------------------------------------------------- /src/assets/title.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/John-rong/Vmovie/HEAD/src/assets/title.jpg -------------------------------------------------------------------------------- /src/assets/user.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/John-rong/Vmovie/HEAD/src/assets/user.png -------------------------------------------------------------------------------- /src/assets/vlogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/John-rong/Vmovie/HEAD/src/assets/vlogo.png -------------------------------------------------------------------------------- /src/assets/film2.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/John-rong/Vmovie/HEAD/src/assets/film2.webp -------------------------------------------------------------------------------- /src/assets/film3.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/John-rong/Vmovie/HEAD/src/assets/film3.webp -------------------------------------------------------------------------------- /src/assets/film4.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/John-rong/Vmovie/HEAD/src/assets/film4.webp -------------------------------------------------------------------------------- /src/assets/slider1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/John-rong/Vmovie/HEAD/src/assets/slider1.jpg -------------------------------------------------------------------------------- /src/assets/slider2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/John-rong/Vmovie/HEAD/src/assets/slider2.jpg -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/cli-plugin-babel/preset' 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /src/assets/lazyLoading.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/John-rong/Vmovie/HEAD/src/assets/lazyLoading.png -------------------------------------------------------------------------------- /src/assets/icons8-loading-30.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/John-rong/Vmovie/HEAD/src/assets/icons8-loading-30.png -------------------------------------------------------------------------------- /src/assets/loader-circle-regular-24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/John-rong/Vmovie/HEAD/src/assets/loader-circle-regular-24.png -------------------------------------------------------------------------------- /src/components/ErrorComponent.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | 13 | 19 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | 6 | # local env files 7 | .env.local 8 | .env.*.local 9 | 10 | # Log files 11 | npm-debug.log* 12 | yarn-debug.log* 13 | yarn-error.log* 14 | pnpm-debug.log* 15 | 16 | # Editor directories and files 17 | .idea 18 | .vscode 19 | *.suo 20 | *.ntvs* 21 | *.njsproj 22 | *.sln 23 | *.sw? 24 | -------------------------------------------------------------------------------- /jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "esnext", 5 | "baseUrl": "./", 6 | "moduleResolution": "node", 7 | "paths": { 8 | "@/*": [ 9 | "src/*" 10 | ] 11 | }, 12 | "lib": [ 13 | "esnext", 14 | "dom", 15 | "dom.iterable", 16 | "scripthost" 17 | ] 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/components/LoadingComponent.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 14 | 15 | -------------------------------------------------------------------------------- /src/layout/LayoutContent.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 25 | 26 | -------------------------------------------------------------------------------- /vue.config.js: -------------------------------------------------------------------------------- 1 | const { defineConfig } = require('@vue/cli-service') 2 | 3 | const AutoImport = require('unplugin-auto-import/webpack'); 4 | const Components = require('unplugin-vue-components/webpack'); 5 | const { TDesignResolver } = require('unplugin-vue-components/resolvers'); 6 | 7 | module.exports = defineConfig({ 8 | transpileDependencies: true, 9 | configureWebpack: { 10 | externals: { 11 | vue: 'Vue', 12 | 'vue-router': 'VueRouter', 13 | axios: 'axios', 14 | less: 'less' 15 | }, 16 | plugins: [ 17 | AutoImport({ 18 | resolvers: [TDesignResolver()], 19 | }), 20 | Components({ 21 | resolvers: [TDesignResolver()], 22 | }), 23 | ] 24 | } 25 | }) 26 | 27 | 28 | -------------------------------------------------------------------------------- /src/utils/lazyLoadView.js: -------------------------------------------------------------------------------- 1 | function lazyLoadView(AsyncView) { 2 | const AsyncComponent = () => ({ 3 | // 需要加载的组件 (应该是一个 `Promise` 对象) 4 | component: AsyncView, 5 | // 异步组件加载时使用的组件 6 | loading: require('@/components/LoadingComponent'), 7 | // 加载失败时使用的组件 8 | error: require('@/components/ErrorComponent'), 9 | // 展示加载时组件的延时时间。默认值是 200 (毫秒) 10 | delay: 200, 11 | // 如果提供了超时时间且组件加载也超时了, 12 | // 则使用加载失败时使用的组件。默认值是:`Infinity` 13 | timeout: 30000 14 | }); 15 | return Promise.resolve({ 16 | functional: true, 17 | // render(h, { data, children }) { 18 | // return h(AsyncComponent, data, children) 19 | // } 20 | render(h) { 21 | return h(AsyncComponent) 22 | } 23 | }); 24 | 25 | } 26 | 27 | export default lazyLoadView; 28 | 29 | 30 | -------------------------------------------------------------------------------- /src/components/DetailTop.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /src/pages/HomePage.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 32 | 33 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vmovie 2 |
3 | 4 | 5 | 6 | 7 | 8 |

vmovie

9 | 10 | 一款电影推荐&在线观看的网站 11 | 12 | 13 | | 主页 :house: | 演示 :beers: | 文档 :memo: | 14 | | ---------------------------------------------------- | ------------------------------------------------- | ------------------------------------------------------ | 15 | | [website](https://github.com/John-rong/Vmovie) | [demo](http://hxtia.top/) | [docs](https://ldgay9zufs.feishu.cn/docx/MIlQdcDQso5Hp2xaOmHcqOqQn6g) | 16 | 17 | ![image](https://hx.404fwf.cn/upload/files/2023_07_582f5f03dde6986328f1766a82b6d4d7.jpeg) 18 | 19 |
20 | 21 | 22 | # :dart: 兼容环境 23 | 24 | - 现代浏览器(Chrome >= 64, Edge >= 79, Firefox >= 78, Safari >= 12) 25 | 26 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | <%= htmlWebpackPlugin.options.title %> 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 24 |
25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /src/components/ThirdSwiper.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 15 | 60 | 61 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './App.vue' 3 | 4 | // //引入TDesign 5 | // import TDesign from 'tdesign-vue'; 6 | // // 引入组件库全局样式资源 7 | // import 'tdesign-vue/es/style/index.css'; 8 | // Vue.use(TDesign); 9 | import VueCompositionAPI from '@vue/composition-api'; 10 | // 引入组件库的少量全局样式变量 11 | import 'tdesign-vue/es/style/index.css'; 12 | Vue.use(VueCompositionAPI); 13 | 14 | //引入全局消息提示 15 | import { MessagePlugin } from 'tdesign-vue' 16 | Vue.prototype.$message = MessagePlugin 17 | 18 | //引入less 19 | import less from 'less' 20 | Vue.use(less) 21 | 22 | //引入路由 23 | import router from '@/router' 24 | 25 | //引入仓库 26 | import store from '@/store' 27 | 28 | //引入图片懒加载 29 | import VueLazyload from 'vue-lazyload' 30 | const loadimage = require('./assets/lazyLoading.png') 31 | const errorimage = require('./assets/vlogo.png') 32 | Vue.use(VueLazyload, { 33 | preLoad: 1.3, 34 | error: errorimage, 35 | loading: loadimage, 36 | attempt: 3 37 | }) 38 | 39 | //自定义指令-防止按钮连续点击 40 | Vue.directive('throttle', { 41 | inserted(el, binding) { 42 | el.addEventListener('click', () => { 43 | el.style.pointerEvents = 'none'; 44 | if (!el.disabled) { 45 | setTimeout(() => { 46 | el.style.pointerEvents = 'auto'; 47 | }, binding.value || 100); 48 | } 49 | }) 50 | } 51 | }) 52 | 53 | //延迟函数 54 | Vue.directive('preventReClick', { 55 | inserted: function (el, binding) { 56 | el.addEventListener('click', () => { 57 | if (!el.disabled) { 58 | el.disabled = true 59 | setTimeout(() => { 60 | el.disabled = false 61 | }, binding.value || 300) 62 | } 63 | }) 64 | } 65 | }); 66 | 67 | Vue.config.productionTip = false 68 | 69 | new Vue({ 70 | render: h => h(App), 71 | router, 72 | store 73 | }).$mount('#app') 74 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 18 | 19 | 84 | 85 | -------------------------------------------------------------------------------- /src/api/request.js: -------------------------------------------------------------------------------- 1 | //axios进行二次封装 2 | import store from '@/store'; 3 | import axios from 'axios'; 4 | 5 | // let reqNum = 0; 6 | //利用axios对象的方法creat,去创建一个axios实例 7 | //request就是axios,再稍微配置一下 8 | const requests = axios.create({ 9 | 10 | //配置对象 基础路径 11 | // baseURL: "/api", 12 | //请求时间 10s超时 13 | timeout: 10000 14 | 15 | }); 16 | 17 | //请求拦截器:发请求之前,请求拦截器可以检测到,可以在请求发出去之前拦截 18 | requests.interceptors.request.use(config => { 19 | // let WhiteList = ['https://console-mock.apipost.cn/app/mock/project/f4b5eed3-856b-4b0a-9ad3-f26bca3ea207/ajax/movieOnInfoList','https://console-mock.apipost.cn/app/mock/project/f4b5eed3-856b-4b0a-9ad3-f26bca3ea207/comingList','http://nfq2hztm.hk2.wknwct.top/api/userinfo'] 20 | // let reqUrl = config.url; 21 | // if(WhiteList.includes(reqUrl)){ 22 | // store.dispatch('beginLoading'); 23 | // reqNum++; 24 | // } 25 | //需要携带token给服务器 26 | if (store.state.token) { 27 | config.headers.token = store.state.token 28 | } 29 | return config; 30 | }); 31 | 32 | //响应拦截器 33 | requests.interceptors.response.use( 34 | res => { 35 | // if(reqNum<0){ 36 | // store.dispatch('endLoading'); 37 | // reqNum++; 38 | // return res.data; 39 | // } 40 | // reqNum--; 41 | // if(reqNum == 0) store.dispatch('endLoading'); 42 | return res.data; 43 | }, 44 | error => { 45 | console.log(error); 46 | // if(reqNum<0){ 47 | // store.dispatch('endLoading'); 48 | // reqNum++; 49 | // return Promise.reject(new Error('faile')); 50 | // } 51 | // reqNum--; 52 | // if(reqNum == 0) store.dispatch('endLoading'); 53 | return Promise.reject(new Error('faile')); 54 | } 55 | ); 56 | 57 | //对外暴露 58 | export default requests; -------------------------------------------------------------------------------- /src/utils/aes.js: -------------------------------------------------------------------------------- 1 | // import CryptoJS from 'crypto-js' 2 | const CryptoJS = require("crypto-js"); 3 | 4 | //加密 5 | export function Encrypt(word, keyStr) { 6 | const key = keyStr || "vmovieeeee1234"; 7 | const ciphertext = CryptoJS.AES.encrypt(word, key).toString(); 8 | return ciphertext; 9 | } 10 | 11 | //解密 12 | export function Decrypt(word, keyStr) { 13 | const key = keyStr || "vmovieeeee1234"; 14 | const bytes = CryptoJS.AES.decrypt(word, key); 15 | const originalText = bytes.toString(CryptoJS.enc.Utf8); 16 | return originalText; 17 | } 18 | 19 | 20 | // let statickey = CryptoJS.enc.Utf8.parse("vmovieeeee1234"); 21 | // let staticiv = CryptoJS.enc.Utf8.parse("1234vvvvvvomive"); 22 | // //加密 23 | // export function Encrypt(word, keyStr, ivStr) { 24 | // const key = CryptoJS.enc.Utf8.parse(keyStr) || statickey; 25 | // const iv = CryptoJS.enc.Utf8.parse(ivStr) || staticiv; 26 | 27 | // let srcs = CryptoJS.enc.Utf8.parse(word); 28 | // //对称解密算法为AES-128-CBC 数据采用PKCS#7填充,key为16位 29 | // let encrypted = CryptoJS.AES.encrypt(srcs, key, { 30 | // iv: iv, 31 | // mode: CryptoJS.mode.CBC, 32 | // padding: CryptoJS.pad.Pkcs7 33 | // }); 34 | // return encrypted.ciphertext.toString().toUpperCase(); 35 | // } 36 | // //解密 37 | // export function Decrypt(word, keyStr, ivStr) { 38 | // const key = CryptoJS.enc.Utf8.parse(keyStr) || statickey; 39 | // const iv = CryptoJS.enc.Utf8.parse(ivStr) || staticiv; 40 | 41 | // let encryptedHexStr = CryptoJS.enc.Hex.parse(word); 42 | // let srcs = CryptoJS.enc.Base64.stringify(encryptedHexStr); 43 | // let decrypt = CryptoJS.AES.decrypt(srcs, key, { 44 | // iv: iv, 45 | // mode: CryptoJS.mode.CBC, 46 | // padding: CryptoJS.pad.Pkcs7 47 | // }); 48 | // let decryptedStr = decrypt.toString(CryptoJS.enc.Utf8); 49 | // return decryptedStr.toString(); 50 | // } 51 | 52 | -------------------------------------------------------------------------------- /src/router/routes.js: -------------------------------------------------------------------------------- 1 | import lazyLoadView from '@/utils/lazyLoadView' 2 | 3 | // //引入路由组件 4 | const HomePage = () => lazyLoadView(import('@/pages/HomePage')) 5 | // const UserLogin = () => lazyLoadView(import('@/pages/UserLogin')) 6 | // const DetailSearch = () => lazyLoadView(import('@/pages/DetailSearch')) 7 | // const DetailPage = () => lazyLoadView(import('@/pages/DetailPage')) 8 | // const RankingList = () => lazyLoadView(import('@/pages/RankingList')) 9 | // const MyProfile = () => lazyLoadView(import('@/pages/MyProfile')) 10 | // const ForumPage = () => lazyLoadView(import('@/pages/ForumPage')) 11 | 12 | // const HomePage = () => import('@/pages/HomePage') 13 | const UserLogin = () => import('@/pages/UserLogin') 14 | const DetailSearch = () => import('@/pages/DetailSearch') 15 | const DetailPage = () => import('@/pages/DetailPage') 16 | const RankingList = () => import('@/pages/RankingList') 17 | const MyProfile = () => import('@/pages/MyProfile') 18 | const ForumPage = () => import('@/pages/ForumPage') 19 | 20 | export default [ 21 | { 22 | path: '/HomePage', 23 | component: HomePage, 24 | name:'HomePage' 25 | }, 26 | { 27 | path: '/UserLogin', 28 | component: UserLogin, 29 | name:'UserLogin' 30 | }, 31 | { 32 | path: '/DetailSearch/:filmName?', 33 | component: DetailSearch, 34 | name:'DetailSearch' 35 | }, 36 | { 37 | path: '/DetailPage', 38 | component: DetailPage, 39 | name:'DetailPage' 40 | }, 41 | { 42 | path: '/RankingList', 43 | component: RankingList, 44 | name:'RankingList' 45 | }, 46 | { 47 | path: '/MyProfile', 48 | component: MyProfile, 49 | name:'MyProfile' 50 | }, 51 | { 52 | path: '/ForumPage', 53 | component: ForumPage, 54 | name:'ForumPage' 55 | }, 56 | //重定向,当访问/,立马定向到首页 57 | { 58 | path: '/', 59 | redirect: '/HomePage' 60 | }, 61 | ] -------------------------------------------------------------------------------- /src/layout/LayOut.vue: -------------------------------------------------------------------------------- 1 | 25 | 26 | 45 | 46 | 67 | 68 | ../components/forum/FooterView.vue../components/nav/HeaderNav.vue -------------------------------------------------------------------------------- /src/components/TestGame.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 60 | 61 | 82 | -------------------------------------------------------------------------------- /src/components/HelloWorld.vue: -------------------------------------------------------------------------------- 1 | 32 | 33 | 41 | 42 | 43 | 60 | -------------------------------------------------------------------------------- /src/components/SecondSwiper.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 42 | 43 | -------------------------------------------------------------------------------- /src/components/SwiperSvg.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 | 26 | 27 | -------------------------------------------------------------------------------- /src/router/index.js: -------------------------------------------------------------------------------- 1 | //引入vue 2 | import Vue from 'vue' 3 | import VueRouter from 'vue-router' 4 | //使用插件 5 | Vue.use(VueRouter) 6 | //引入路由组件 7 | import routes from './routes' 8 | //引入store 9 | import store from '@/store'; 10 | //引入消息提示 11 | import { MessagePlugin } from 'tdesign-vue' 12 | 13 | //解决编程时导航报错问题 14 | //先把VueRouter原型对象的push,保存一份 15 | let originPush = VueRouter.prototype.push; 16 | let originReplace = VueRouter.prototype.replace; 17 | //重写push | replace 18 | VueRouter.prototype.push = function (location, resolve, reject) { 19 | //第一个参数:告诉原来的push,跳转的目标位置和传递了哪些参数 20 | if (resolve && reject) { 21 | originPush.call(this, location, resolve, reject) 22 | } else { 23 | originPush.call(this, location, () => { }, () => { }) 24 | } 25 | } 26 | VueRouter.prototype.replace = function (location, resolve, reject) { 27 | //第一个参数:告诉原来的push,跳转的目标位置和传递了哪些参数 28 | if (resolve && reject) { 29 | originReplace.call(this, location, resolve, reject) 30 | } else { 31 | originReplace.call(this, location, () => { }, () => { }) 32 | } 33 | } 34 | 35 | //对外暴露VueRouter实例 36 | let router = new VueRouter({ 37 | //配置路由 (省略v) 38 | routes, 39 | //滚动行为 40 | scrollBehavior(to, from, savedPosition) { 41 | // return 期望滚动到哪个的位置 42 | console.log('滚动条', to, from, savedPosition); 43 | return { y: 0 }//滚动条在最上方 44 | } 45 | }); 46 | 47 | //全局守卫,前置守卫(在路由跳转之间进行判断) 48 | router.beforeEach(async (to, from, next) => { 49 | //to:跳转的路由信息 50 | //from:从哪个路由来 51 | //next:放行函数 next()放行 next(path)放行到指定路由 52 | 53 | //登录才有token 54 | let token = store.state.token; 55 | //用户信息 56 | let name = store.state.userInfo.name 57 | //用户已经登录 58 | if (token) { 59 | //阻止登录用户去login 停留在首页 60 | if (to.path === '/UserLogin') { 61 | next('/HomePage') 62 | } else { 63 | //存在用户信息 直接放行 64 | if (name) { 65 | next(); 66 | } else { 67 | //不存在用户信息,派发action让仓库存储信息 68 | try { 69 | //获取用户信息成功 70 | await store.dispatch('userInfo'); 71 | } catch (error) { 72 | //token失效了 清除token 重新登陆 73 | MessagePlugin.warning('登录失效,请重新登录...'); 74 | await store.dispatch('userLogout'); 75 | next('/UserLogin'); 76 | 77 | } 78 | next(); 79 | } 80 | } 81 | } else { 82 | //未登录 主页和login和搜索放行 83 | if (to.path === '/HomePage' || to.path === '/UserLogin' || to.path === '/DetailPage' || to.path === '/DetailSearch' || to.path === '/RankingList') { 84 | next(); 85 | } else { 86 | MessagePlugin.info('请先进行登录...'); 87 | // alert('请先进行登录!') 88 | next('/UserLogin'); 89 | } 90 | } 91 | }); 92 | 93 | export default router; -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vmovie", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "serve": "vue-cli-service serve", 7 | "build": "vue-cli-service build --report", 8 | "lint": "vue-cli-service lint" 9 | }, 10 | "dependencies": { 11 | "axios": "^0.27.2", 12 | "core-js": "^3.8.3", 13 | "crypto-js": "^4.1.1", 14 | "less-loader": "^11.0.0", 15 | "mavon-editor": "^2.10.4", 16 | "tdesign-vue": "^0.43.3", 17 | "vue": "^2.6.14", 18 | "vue-lazyload": "^1.3.3", 19 | "vue-router": "^3.5.4", 20 | "vuex": "^3.6.2" 21 | }, 22 | "devDependencies": { 23 | "@babel/core": "^7.12.16", 24 | "@babel/eslint-parser": "^7.12.16", 25 | "@vue/cli-plugin-babel": "~5.0.0", 26 | "@vue/cli-plugin-eslint": "~5.0.0", 27 | "@vue/cli-service": "~5.0.0", 28 | "eslint": "^7.32.0", 29 | "eslint-plugin-vue": "^8.0.3", 30 | "unplugin-auto-import": "^0.9.2", 31 | "unplugin-vue-components": "^0.21.1", 32 | "vue-template-compiler": "^2.6.14" 33 | }, 34 | "eslintConfig": { 35 | "root": true, 36 | "env": { 37 | "node": true 38 | }, 39 | "extends": [ 40 | "plugin:vue/essential", 41 | "eslint:recommended" 42 | ], 43 | "parserOptions": { 44 | "parser": "@babel/eslint-parser" 45 | }, 46 | "rules": {} 47 | }, 48 | "browserslist": [ 49 | "> 1%", 50 | "last 2 versions", 51 | "not dead" 52 | ] 53 | } 54 | { 55 | "name": "vmovie", 56 | "version": "0.1.0", 57 | "private": true, 58 | "scripts": { 59 | "serve": "vue-cli-service serve", 60 | "build": "vue-cli-service build", 61 | "lint": "vue-cli-service lint" 62 | }, 63 | "dependencies": { 64 | "axios": "^0.27.2", 65 | "core-js": "^3.8.3", 66 | "crypto-js": "^4.1.1", 67 | "less-loader": "^11.0.0", 68 | "mavon-editor": "^2.10.4", 69 | "tdesign-vue": "^0.43.3", 70 | "vue": "^2.6.14", 71 | "vue-lazyload": "^1.3.3", 72 | "vue-router": "^3.5.4", 73 | "vuex": "^3.6.2" 74 | }, 75 | "devDependencies": { 76 | "@babel/core": "^7.12.16", 77 | "@babel/eslint-parser": "^7.12.16", 78 | "@vue/cli-plugin-babel": "~5.0.0", 79 | "@vue/cli-plugin-eslint": "~5.0.0", 80 | "@vue/cli-service": "~5.0.0", 81 | "eslint": "^7.32.0", 82 | "eslint-plugin-vue": "^8.0.3", 83 | "unplugin-auto-import": "^0.9.2", 84 | "unplugin-vue-components": "^0.21.1", 85 | "vue-template-compiler": "^2.6.14" 86 | }, 87 | "eslintConfig": { 88 | "root": true, 89 | "env": { 90 | "node": true 91 | }, 92 | "extends": [ 93 | "plugin:vue/essential", 94 | "eslint:recommended" 95 | ], 96 | "parserOptions": { 97 | "parser": "@babel/eslint-parser" 98 | }, 99 | "rules": {} 100 | }, 101 | "browserslist": [ 102 | "> 1%", 103 | "last 2 versions", 104 | "not dead" 105 | ] 106 | } 107 | -------------------------------------------------------------------------------- /src/components/SwiperWord.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 25 | 26 | -------------------------------------------------------------------------------- /src/api/index.js: -------------------------------------------------------------------------------- 1 | //API接口统一管理 2 | import requests from "./request"; 3 | 4 | //发请求:axios发请求返回结果Promise对象 5 | // export const movieOnInfoList = () => requests({ url: 'https://m.maoyan.com/ajax/movieOnInfoList', method: 'get' }); 6 | 7 | //热映电影列表 mock 8 | export const movieOnInfoList = () => requests({ url: 'https://console-mock.apipost.cn/app/mock/project/f4b5eed3-856b-4b0a-9ad3-f26bca3ea207/ajax/movieOnInfoList', method: 'get' }); 9 | export const reqmovieInfoList = () => requests({ url: 'https://console-mock.apipost.cn/app/mock/project/f4b5eed3-856b-4b0a-9ad3-f26bca3ea207/comingList', method: 'get' }); 10 | 11 | //狙击手电影详情 mock 12 | export const jujishouMovie = () => requests({ url: 'https://console-mock.apipost.cn/app/mock/project/f4b5eed3-856b-4b0a-9ad3-f26bca3ea207/jujishou', method: 'get' }); 13 | 14 | //豆瓣热门排行100 mock 15 | export const reqdbRanking = () => requests({ url: 'https://console-mock.apipost.cn/mock/f4b5eed3-856b-4b0a-9ad3-f26bca3ea207/douban?apipost_id=4fbe31', method: 'get' }); 16 | 17 | //豆瓣排行(跨域) 18 | export const douban = () => requests({ url: 'https://movie.douban.com/j/search_subjects?type=movie&tag=%E7%83%AD%E9%97%A8&page_limit=50&page_start=0', method: 'get' }); 19 | 20 | //注册 http://gmall-h5-api.atguigu.cn/api/user/passport/register post 21 | // export const reqUserRegister = data => requests({ url: 'http://gmall-h5-api.atguigu.cn/api/user/passport/register', data, method: 'post' }); 22 | export const reqUserRegister = data => requests({ url: 'http://404fwf.tk/api/register', data, method: 'post', headers: { "Content-Type": "application/x-www-form-urlencoded" } }); 23 | 24 | //登录 25 | // export const reqUserLogin = data => requests({ url: 'http://gmall-h5-api.atguigu.cn/api/user/passport/login', data, method: 'post'}); 26 | export const reqUserLogin = data => requests({ url: 'http://404fwf.tk/api/login', data, method: 'post', headers: { "Content-Type": "application/x-www-form-urlencoded" } }); 27 | 28 | //获取用户信息【带token】 29 | // export const reqUserInfo = () => requests({ url: 'http://gmall-h5-api.atguigu.cn/api/user/passport/auth/getUserInfo', method: 'get' }); 30 | export const reqUserInfo = () => requests({ url: 'http://404fwf.tk/api/userinfo', method: 'get' }); 31 | 32 | //更新用户信息【带token】 33 | export const reqUpUserInfo = data => requests({ url: 'http://404fwf.tk/api/upuserinfo', data, method: 'post', headers: { "Content-Type": "application/x-www-form-urlencoded" } }); 34 | 35 | //退出登录 36 | export const reqLogout = () => requests({ url: 'http://gmall-h5-api.atguigu.cn/api/user/passport/logout', method: 'get' }); 37 | 38 | //唠嗑主题上传【带token】 39 | export const reqForumAdd = data => requests({ url: 'http://404fwf.tk/api/foruminfo', data, method: 'post', headers: { "Content-Type": "application/x-www-form-urlencoded" } }); 40 | 41 | //文件(图片,md)上传 42 | export const reqUploder = data => requests({ url: 'http://404fwf.tk/api/uploder', data, method: 'post', headers: { "Content-Type": "multipart/form-data" } }); 43 | 44 | //获取唠嗑主题列表 45 | export const reqForumlist = data => requests({ url: `http://404fwf.tk/api/forumlist?currentPage=${data.currentPage}&pageSize=${data.pageSize}`, method: 'get' }); 46 | export const reqSearchForum = data => requests({ url: `http://404fwf.tk/api/forumlist?currentPage=${data.currentPage}&pageSize=${data.pageSize}&title=${data.title}`, method: 'get' }); 47 | 48 | //评论 49 | export const reqComment = data => requests({ url: 'http://404fwf.tk/api/comment', data, method: 'post', headers: { "Content-Type": "application/x-www-form-urlencoded" } }); 50 | 51 | //获取评论 52 | export const reqCommentlist = data => requests({ url: `http://404fwf.tk/api/commentlist?commentid=${data}`, data, method: 'get' }); 53 | -------------------------------------------------------------------------------- /src/pages/DetailPage.vue: -------------------------------------------------------------------------------- 1 | 26 | 27 | 62 | 63 | -------------------------------------------------------------------------------- /src/store/index.js: -------------------------------------------------------------------------------- 1 | import { reqLogout, reqUserInfo, reqUserLogin, reqUserRegister } from '@/api'; 2 | import Vue from 'vue'; 3 | import Vuex from 'vuex'; 4 | //需要使用插件一次 5 | Vue.use(Vuex); 6 | //对外暴露Store类的一个实例 7 | //state:仓库存储数据的地方 8 | const state = { 9 | searchFilm: '', 10 | token: localStorage.getItem('TOKEN'), 11 | userInfo: '', 12 | isloading:false 13 | } 14 | //mutation:修改state的唯一手段 15 | const mutations = { 16 | SEARCHNAME(state, name) { 17 | state.searchFilm = name; 18 | }, 19 | //设置用户token 20 | USERLOGIN(state, token) { 21 | state.token = token 22 | }, 23 | USERINFO(state, userInfo) { 24 | state.userInfo = userInfo 25 | }, 26 | //清除本地用户数据 27 | CLEARUSER(state) { 28 | //清除仓库用户 29 | state.token = ''; 30 | state.userInfo = {}; 31 | //清除本地存储 32 | localStorage.removeItem("TOKEN"); 33 | }, 34 | BEGINLOADING(state){ 35 | state.isloading = true; 36 | }, 37 | ENDLOADING(state){ 38 | state.isloading = false; 39 | } 40 | 41 | } 42 | //actions:处理actions,可以写自己的业务逻辑,也可以处理异步 43 | const actions = { 44 | //无法修改state 45 | searchName({ commit }, name) { 46 | commit('SEARCHNAME', name); 47 | }, 48 | //用户注册 49 | async userRegister({ commit }, user) { 50 | let arr = []; 51 | let fromuser=''; 52 | for (const key in user) { 53 | arr.push(`${key}=${user[key]}`) 54 | } 55 | fromuser += arr.join('&'); 56 | console.log('uuuu',fromuser) 57 | 58 | let result = await reqUserRegister(fromuser); 59 | console.log(commit) 60 | // console.log('注册',result, commit) 61 | if (result.code == 200) { 62 | return 'ok'; 63 | }else if(result.code == 400){ 64 | const msg = result.meta.msg 65 | return Promise.reject(new Error(msg)) 66 | }else { 67 | return Promise.reject(new Error('注册失败...')) 68 | } 69 | }, 70 | //用户登录 71 | async userLogin({ commit }, data) { 72 | let arr = []; 73 | let fromData=''; 74 | for (const key in data) { 75 | arr.push(`${key}=${data[key]}`) 76 | } 77 | fromData += arr.join('&'); 78 | 79 | let result = await reqUserLogin(fromData); 80 | // console.log('用户登录', result) 81 | //服务器返回token 82 | if (result.code == 200) { 83 | //在vuex保存token 84 | commit("USERLOGIN", result.data.token); 85 | //持久化存储token 86 | localStorage.setItem("TOKEN", result.data.token) 87 | return 'ok'; 88 | }else if(result.code == 201 || result.code == 202 || result.code == 400){ 89 | const msg = result.meta.msg 90 | return Promise.reject(new Error(msg)); 91 | }else { 92 | return Promise.reject(new Error('登录失败...')); 93 | } 94 | }, 95 | //获取用户信息 96 | async userInfo({ commit }) { 97 | let result = await reqUserInfo(); 98 | // console.log('登录信息', result) 99 | if (result.code == 200) { 100 | //保存用户信息 101 | commit("USERINFO", result.data); 102 | return 'ok'; 103 | } else { 104 | return Promise.reject(new Error('faile')); 105 | } 106 | }, 107 | //退出登录 108 | async userLogout({ commit }) { 109 | //向服务器发请求,通知服务器清除token 110 | // let result = await reqLogout(); 111 | // if (result.code == 200) { 112 | // commit("CLEARUSER"); 113 | // return 'ok'; 114 | // } else { 115 | // return Promise.reject(new Error('faile')) 116 | // } 117 | console.log('已退出登录',reqLogout) 118 | commit("CLEARUSER"); 119 | return 'ok'; 120 | }, 121 | //加载loading 122 | beginLoading({commit}){ 123 | commit('BEGINLOADING'); 124 | }, 125 | //隐藏loading 126 | endLoading({commit}){ 127 | commit('ENDLOADING'); 128 | } 129 | 130 | } 131 | //getters:理解为计算属性,用于简化仓库数据,让组件获得仓库的数据更加方便 132 | const getters = {} 133 | 134 | export default new Vuex.Store({ 135 | state, 136 | mutations, 137 | actions, 138 | getters 139 | }) -------------------------------------------------------------------------------- /src/pages/DetailSearch.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 108 | 109 | -------------------------------------------------------------------------------- /src/components/ForumAdd.vue: -------------------------------------------------------------------------------- 1 | 25 | 26 | 119 | 120 | -------------------------------------------------------------------------------- /src/components/FooterView.vue: -------------------------------------------------------------------------------- 1 | 75 | 76 | 81 | 82 | -------------------------------------------------------------------------------- /src/components/FilmItem.vue: -------------------------------------------------------------------------------- 1 | 38 | 39 | 110 | 111 | -------------------------------------------------------------------------------- /src/pages/UserLogin.vue: -------------------------------------------------------------------------------- 1 | 41 | 42 | 126 | 127 | -------------------------------------------------------------------------------- /src/components/HeaderNav.vue: -------------------------------------------------------------------------------- 1 | 67 | 68 | 165 | 166 | -------------------------------------------------------------------------------- /src/components/ForumDetail.vue: -------------------------------------------------------------------------------- 1 | 54 | 55 | 183 | 184 | -------------------------------------------------------------------------------- /src/pages/MyProfile.vue: -------------------------------------------------------------------------------- 1 | 57 | 58 | 186 | 187 | -------------------------------------------------------------------------------- /src/components/ThirdSwiperFirst.vue: -------------------------------------------------------------------------------- 1 | 27 | 201 | 202 | -------------------------------------------------------------------------------- /src/components/FirstSwiper.vue: -------------------------------------------------------------------------------- 1 | 60 | 61 | 153 | 154 | -------------------------------------------------------------------------------- /src/pages/ForumPage.vue: -------------------------------------------------------------------------------- 1 | 84 | 85 | 207 | 208 | -------------------------------------------------------------------------------- /src/pages/RankingList.vue: -------------------------------------------------------------------------------- 1 | 106 | 107 | 309 | 310 | -------------------------------------------------------------------------------- /src/components/ThirdSwiperSecond.vue: -------------------------------------------------------------------------------- 1 | 64 | 65 | 149 | 150 | 499 | 500 | 501 | 502 | 503 | 504 | 632 | --------------------------------------------------------------------------------