├── .prettierignore ├── .eslintignore ├── server └── tsconfig.json ├── assets ├── .DS_Store ├── image │ ├── gzh.jpg │ ├── gzh.png │ ├── phone.png │ ├── common_head.jpg │ └── common_login.png ├── svg │ ├── account │ │ ├── user.svg │ │ ├── course.svg │ │ ├── mobile.svg │ │ ├── wechat.svg │ │ ├── collect.svg │ │ ├── password.svg │ │ └── order.svg │ ├── phone.svg │ ├── comment.svg │ ├── gzh.svg │ └── chapter.svg └── styles │ └── main.scss ├── components ├── .DS_Store ├── Zone │ ├── Banner.vue │ ├── Course.vue │ └── Category.vue ├── Course │ ├── Collect.vue │ ├── Choose.vue │ ├── List.vue │ ├── Comment.vue │ └── Chapter.vue ├── Common │ ├── Affix.vue │ ├── Link.vue │ ├── Pagination.vue │ ├── User.vue │ ├── Footer.vue │ ├── Header.vue │ └── Pay.vue ├── Lecturer │ └── List.vue └── Account │ ├── Wechat.vue │ └── Order.vue ├── public └── favicon.ico ├── distribution ├── images │ ├── gzh.png │ ├── admin1.png │ ├── admin2.png │ ├── admin3.png │ ├── admin4.png │ ├── logo.jpg │ ├── web1.png │ ├── web2.png │ ├── web3.png │ └── web4.png ├── bin │ └── web.sh ├── assembly.xml └── pom.xml ├── tsconfig.json ├── plugins ├── error-handler.js └── element-plus.js ├── app.vue ├── .env.production ├── api ├── upload.js ├── lecturer.js ├── index.js ├── login.js ├── user.js └── course.js ├── .env.development ├── ecosystem.config.js ├── eslint.config.cjs ├── .prettierrc.json ├── middleware └── router.global.js ├── .gitignore ├── layouts ├── default.vue └── account.vue ├── utils ├── login.js ├── cookie.js ├── table.js ├── polyv.js ├── storage.js ├── request.js └── base.js ├── pages ├── 404.vue ├── index.vue ├── account │ ├── order.vue │ ├── collect.vue │ ├── course.vue │ └── user.vue ├── lecturer │ ├── list.vue │ └── detail.vue ├── search.vue ├── course │ ├── list.vue │ ├── detail.vue │ └── study.vue ├── register.vue ├── reset.vue └── login.vue ├── zip.mjs ├── nuxt.config.ts ├── LICENSE.txt ├── package.json └── README.md /.prettierignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | .prettierrc.json 4 | -------------------------------------------------------------------------------- /server/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../.nuxt/tsconfig.server.json" 3 | } 4 | -------------------------------------------------------------------------------- /assets/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/roncoo/roncoo-education-web/HEAD/assets/.DS_Store -------------------------------------------------------------------------------- /assets/image/gzh.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/roncoo/roncoo-education-web/HEAD/assets/image/gzh.jpg -------------------------------------------------------------------------------- /assets/image/gzh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/roncoo/roncoo-education-web/HEAD/assets/image/gzh.png -------------------------------------------------------------------------------- /components/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/roncoo/roncoo-education-web/HEAD/components/.DS_Store -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/roncoo/roncoo-education-web/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /assets/image/phone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/roncoo/roncoo-education-web/HEAD/assets/image/phone.png -------------------------------------------------------------------------------- /distribution/images/gzh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/roncoo/roncoo-education-web/HEAD/distribution/images/gzh.png -------------------------------------------------------------------------------- /assets/image/common_head.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/roncoo/roncoo-education-web/HEAD/assets/image/common_head.jpg -------------------------------------------------------------------------------- /assets/image/common_login.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/roncoo/roncoo-education-web/HEAD/assets/image/common_login.png -------------------------------------------------------------------------------- /distribution/images/admin1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/roncoo/roncoo-education-web/HEAD/distribution/images/admin1.png -------------------------------------------------------------------------------- /distribution/images/admin2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/roncoo/roncoo-education-web/HEAD/distribution/images/admin2.png -------------------------------------------------------------------------------- /distribution/images/admin3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/roncoo/roncoo-education-web/HEAD/distribution/images/admin3.png -------------------------------------------------------------------------------- /distribution/images/admin4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/roncoo/roncoo-education-web/HEAD/distribution/images/admin4.png -------------------------------------------------------------------------------- /distribution/images/logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/roncoo/roncoo-education-web/HEAD/distribution/images/logo.jpg -------------------------------------------------------------------------------- /distribution/images/web1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/roncoo/roncoo-education-web/HEAD/distribution/images/web1.png -------------------------------------------------------------------------------- /distribution/images/web2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/roncoo/roncoo-education-web/HEAD/distribution/images/web2.png -------------------------------------------------------------------------------- /distribution/images/web3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/roncoo/roncoo-education-web/HEAD/distribution/images/web3.png -------------------------------------------------------------------------------- /distribution/images/web4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/roncoo/roncoo-education-web/HEAD/distribution/images/web4.png -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | // https://nuxt.com/docs/guide/concepts/typescript 3 | "extends": "./.nuxt/tsconfig.json" 4 | } 5 | -------------------------------------------------------------------------------- /plugins/error-handler.js: -------------------------------------------------------------------------------- 1 | export default defineNuxtPlugin((nuxtApp) => { 2 | nuxtApp.hook('vue:error', (err) => { 3 | console.error(err) 4 | // 这里可以记录错误日志 5 | }) 6 | }) 7 | -------------------------------------------------------------------------------- /app.vue: -------------------------------------------------------------------------------- 1 | 4 | 9 | -------------------------------------------------------------------------------- /.env.production: -------------------------------------------------------------------------------- 1 | # 生产环境 2 | NODE_ENV = production 3 | # 后端接口地址 4 | VITE_BASE_URL = 'http://localhost/gateway' 5 | # 是否删除console 6 | VITE_DROP_CONSOLE = true 7 | # 是否删除debugger 8 | VITE_DROP_DEBUGGER = true 9 | -------------------------------------------------------------------------------- /api/upload.js: -------------------------------------------------------------------------------- 1 | import { upload } from '@/utils/request' 2 | 3 | export const uploadApi = { 4 | // 上传图片 5 | uploadPic: (file) => { 6 | return upload('/system/auth/upload/pic', file) 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /.env.development: -------------------------------------------------------------------------------- 1 | # 开发环境 2 | NODE_ENV = development 3 | # 后端接口地址 4 | VITE_BASE_URL = 'http://localhost:7700' 5 | # 是否删除console 6 | VITE_DROP_CONSOLE = false 7 | # 是否删除debugger 8 | VITE_DROP_DEBUGGER = false 9 | -------------------------------------------------------------------------------- /ecosystem.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | apps: [ 3 | { 4 | name: 'web', // 名称 5 | script: '.output/server/index.mjs', 6 | instances: '1' // 进程数,若为:max,指当前服务器cpu核数 7 | } 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /eslint.config.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | rules: { 3 | 'linebreak-style': 0, 4 | 'space-before-function-paren': 0, 5 | 'vue/no-multiple-template-root': 'off', 6 | 'vue/multi-word-component-names': 'off' 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /plugins/element-plus.js: -------------------------------------------------------------------------------- 1 | import ElementPlus from 'element-plus' 2 | import zhCn from 'element-plus/dist/locale/zh-cn.js' 3 | export default defineNuxtPlugin((nuxtApp) => { 4 | nuxtApp.vueApp.use(ElementPlus, { locale: zhCn }) 5 | }) 6 | -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/prettierrc", 3 | "semi": false, 4 | "tabWidth": 2, 5 | "singleQuote": true, 6 | "printWidth": 200, 7 | "trailingComma": "none", 8 | "vueIndentScriptAndStyle": true 9 | } 10 | -------------------------------------------------------------------------------- /middleware/router.global.js: -------------------------------------------------------------------------------- 1 | export default defineNuxtRouteMiddleware((to) => { 2 | // 首页重定向 3 | if (to.path === '/index') { 4 | return navigateTo('/') 5 | } 6 | 7 | // 404页面 8 | if (to.matched.length === 0) { 9 | return navigateTo('/404') 10 | } 11 | }) 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | npm-debug.log* 4 | yarn-debug.log* 5 | web.zip 6 | 7 | .nuxt 8 | .output 9 | .DS_Store 10 | .idea 11 | .vscode 12 | 13 | *.suo 14 | *.ntvs* 15 | *.njsproj 16 | *.sln 17 | *.classpath 18 | *.project 19 | *.settings 20 | *.mvn 21 | *.springBeans 22 | *.factorypath 23 | 24 | distribution/target 25 | package-lock.json 26 | pnpm-lock.yaml 27 | -------------------------------------------------------------------------------- /layouts/default.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 18 | -------------------------------------------------------------------------------- /api/lecturer.js: -------------------------------------------------------------------------------- 1 | import { getRequest, postRequest } from '@/utils/request' 2 | 3 | export const lecturerApi = { 4 | // 讲师列表(搜索) 5 | lecturerList: (params = {}) => { 6 | return postRequest('/user/api/lecturer/search', params) 7 | }, 8 | 9 | // 讲师详情 10 | lecturerDetail: (params = {}) => { 11 | return getRequest('/user/api/lecturer/view?id=' + params.id) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /utils/login.js: -------------------------------------------------------------------------------- 1 | import { setToken, removeToken } from '@/utils/cookie' 2 | import { setStorage, getStorage } from '@/utils/storage' 3 | 4 | export const login = (token) => { 5 | setToken(token) 6 | const history = getStorage('history') 7 | if (history) { 8 | window.location.href = history 9 | setStorage('history', '') 10 | } else { 11 | window.location.href = '/' 12 | } 13 | } 14 | 15 | export const logout = () => { 16 | removeToken() 17 | } 18 | -------------------------------------------------------------------------------- /distribution/bin/web.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright 2016-现在 LingKe, Co., Ltd. 3 | export NODE_HOME=/opt/node 4 | export PM2="$NODE_HOME/bin/pm2" 5 | export BASE_DIR=`cd $(dirname $0)/..; pwd` 6 | export SERVER="web" 7 | 8 | case "$1" in 9 | start) 10 | cd ${BASE_DIR} 11 | if [ ! -d "node_modules" ];then 12 | npm install 13 | fi 14 | ${PM2} start 15 | echo "${SERVER} start success" 16 | ;; 17 | stop) 18 | ${PM2} stop ${SERVER} 19 | ${PM2} delete ${SERVER} 20 | echo "${SERVER} stop success" 21 | ;; 22 | *) 23 | $0 stop 24 | sleep 1 25 | $0 start 26 | ;; 27 | esac 28 | -------------------------------------------------------------------------------- /pages/404.vue: -------------------------------------------------------------------------------- 1 | 11 | 22 | 27 | -------------------------------------------------------------------------------- /pages/index.vue: -------------------------------------------------------------------------------- 1 | 10 | 25 | 26 | -------------------------------------------------------------------------------- /assets/svg/account/user.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /zip.mjs: -------------------------------------------------------------------------------- 1 | /** 2 | * 打包工具,方便将打包后的dist进行管理,打包后的文件为:web.zip 3 | */ 4 | import { createWriteStream } from 'fs' 5 | import path from 'path' 6 | import archiver from 'archiver' 7 | 8 | const output = createWriteStream(path.resolve('./web.zip')) 9 | const archive = archiver('zip', { zlib: { level: 9 } }) 10 | 11 | archive.pipe(output) 12 | archive.directory(path.resolve('node_modules'), 'node_modules', null) 13 | archive.directory(path.resolve('.output'), '.output', null) 14 | archive.directory(path.resolve('distribution', 'bin'), 'bin', null) 15 | archive.file(path.resolve('ecosystem.config.js'), { name: 'ecosystem.config.js' }) 16 | archive.file(path.resolve('nuxt.config.ts'), { name: 'nuxt.config.ts' }) 17 | archive.file(path.resolve('package.json'), { name: 'package.json' }) 18 | 19 | archive.finalize().then(() => { 20 | console.log('打包成功,请查看根目录下的:web.zip') 21 | }) 22 | -------------------------------------------------------------------------------- /pages/account/order.vue: -------------------------------------------------------------------------------- 1 | 10 | 31 | 32 | -------------------------------------------------------------------------------- /api/index.js: -------------------------------------------------------------------------------- 1 | import { getRequest, postRequest } from '@/utils/request' 2 | 3 | export const indexApi = { 4 | // 首页轮播图 5 | carouselList: () => { 6 | return getRequest('/system/api/website/carousel/list') 7 | }, 8 | // 分类列表 9 | categoryList: () => { 10 | return getRequest('/course/api/category/list') 11 | }, 12 | // 专区课程 13 | zoneList: (params = {}) => { 14 | return postRequest('/course/api/zone/list', params) 15 | }, 16 | // 首页导航栏 17 | websiteNav: () => { 18 | return getRequest('/system/api/website/nav/list') 19 | }, 20 | // 站点信息 21 | websiteInfo: () => { 22 | return getRequest('/system/api/sys/config/website') 23 | }, 24 | // 友情链接 25 | websiteLink: () => { 26 | return getRequest('/system/api/website/link/list') 27 | }, 28 | // 获取枚举 29 | getEnum: (data) => { 30 | return postRequest('/system/api/common/enum', data) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /assets/svg/account/course.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /utils/cookie.js: -------------------------------------------------------------------------------- 1 | import Cookies from 'js-cookie' 2 | 3 | /** 4 | * token的key 5 | */ 6 | const TOKEN_KEY = 'EDU_OS_TOKEN' 7 | /** 8 | * 单位:天 9 | */ 10 | const TokenExpiresTime = 1 11 | 12 | export function setToken(token) { 13 | return Cookies.set(TOKEN_KEY, token, { 14 | expires: TokenExpiresTime 15 | }) 16 | } 17 | 18 | export function getToken() { 19 | if (process.server) { 20 | const nuxtApp = useNuxtApp() 21 | return getTokenForServer(nuxtApp.ssrContext.event.node.req) 22 | } 23 | return Cookies.get(TOKEN_KEY) 24 | } 25 | 26 | export function removeToken() { 27 | return Cookies.remove(TOKEN_KEY, { 28 | expires: 0 29 | }) 30 | } 31 | 32 | function getTokenForServer(req) { 33 | const serviceCookie = {} 34 | req && 35 | req.headers.cookie && 36 | req.headers.cookie.split(';').forEach(function (val) { 37 | const parts = val.split('=') 38 | serviceCookie[parts[0].trim()] = decodeURIComponent((parts[1] || '').trim()) 39 | }) 40 | return serviceCookie.EDU_OS_TOKEN 41 | } 42 | -------------------------------------------------------------------------------- /nuxt.config.ts: -------------------------------------------------------------------------------- 1 | // https://nuxt.com/docs/api/configuration/nuxt-config 2 | // eslint-disable-next-line no-undef 3 | export default defineNuxtConfig({ 4 | experimental: { 5 | asyncContext: true 6 | }, 7 | css: ['~/assets/styles/main.scss'], 8 | modules: ['@element-plus/nuxt', '@vueuse/nuxt'], 9 | nitro: { 10 | devProxy: { 11 | '/gateway': { 12 | target: import.meta.env.VITE_BASE_URL, 13 | changeOrigin: true 14 | } 15 | } 16 | }, 17 | vite: { 18 | build: { 19 | minify: 'terser', 20 | emptyOutDir: true, 21 | chunkSizeWarningLimit: 1500, 22 | terserOptions: { 23 | compress: { 24 | drop_console: import.meta.env.VITE_DROP_CONSOLE, 25 | drop_debugger: import.meta.env.VITE_DROP_DEBUGGER 26 | } 27 | } 28 | } 29 | }, 30 | sourcemap: { 31 | server: import.meta.env.NODE_ENV === 'development', 32 | client: import.meta.env.NODE_ENV === 'development' 33 | }, 34 | telemetry: true, 35 | compatibilityDate: '2025-08-25' 36 | }) 37 | -------------------------------------------------------------------------------- /api/login.js: -------------------------------------------------------------------------------- 1 | import { postRequest, getRequest } from '@/utils/request' 2 | 3 | export const loginApi = { 4 | // 密码登录 5 | userLogin: (params = {}) => { 6 | return postRequest('/user/api/users/login', params) 7 | }, 8 | // 微信登录 9 | wxLogin: (params = {}) => { 10 | return postRequest('/user/api/users/wx/login', params) 11 | }, 12 | // 微信登录 13 | wxCode: (params = {}) => { 14 | return postRequest('/user/api/users/wx/code', params) 15 | }, 16 | // 微信登录 17 | wxBinding: (params = {}) => { 18 | return postRequest('/user/api/users/wx/binding', params) 19 | }, 20 | getCodeImg: () => { 21 | return getRequest('/system/api/common/code') 22 | }, 23 | // 发送注册验证码 24 | getMobileCode: (params) => { 25 | return postRequest('/user/api/users/send/code', params) 26 | }, 27 | // 用户注册 28 | register: (params = {}) => { 29 | return postRequest('/user/api/users/register', params) 30 | }, 31 | // 修改密码 32 | updatePassword: (params = {}) => { 33 | return postRequest('/user/api/users/password', params) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright © 2016 LingKe, Co., Ltd. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /assets/styles/main.scss: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | font-size: 12px; 5 | background-color: #f6f8fb; 6 | height: 100vh; 7 | overflow: hidden; 8 | word-break: break-all; 9 | } 10 | a { 11 | text-decoration: none; 12 | color: inherit; 13 | } 14 | .main { 15 | width: 1200px; 16 | margin: 0 auto; 17 | } 18 | .pagination { 19 | display: flex; 20 | justify-content: center; 21 | margin: 20px 0; 22 | } 23 | .clearfix { 24 | clear: both; 25 | } 26 | .cursor { 27 | cursor: pointer; 28 | } 29 | .fl { 30 | float: left; 31 | } 32 | .fr { 33 | float: right; 34 | } 35 | .title { 36 | overflow: hidden; 37 | text-overflow: ellipsis; 38 | -webkit-line-clamp: 2; 39 | -webkit-box-orient: vertical; 40 | } 41 | // 42 | .no-data { 43 | margin: calc((100vh - 346px) / 2) auto; 44 | text-align: center; 45 | font-size: 20px; 46 | } 47 | 48 | // 滚动条样式 49 | ::-webkit-scrollbar { 50 | width: 5px; 51 | height: 5px; 52 | border-radius: 5px; 53 | } 54 | 55 | ::-webkit-scrollbar-thumb { 56 | border-radius: 5px; 57 | background: rgba(0, 0, 0, 0.2); 58 | } 59 | 60 | ::-webkit-scrollbar-track { 61 | border-radius: 0; 62 | background: #fff; 63 | } 64 | -------------------------------------------------------------------------------- /components/Zone/Banner.vue: -------------------------------------------------------------------------------- 1 | 14 | 22 | 41 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "roncoo-education-web", 3 | "version": "25.0.0-RELEASE", 4 | "license": "MIT", 5 | "type": "commonjs", 6 | "scripts": { 7 | "dev": "nuxt dev --dotenv .env.development", 8 | "build": "nuxt build --dotenv .env.production", 9 | "lint": "eslint . --fix --ext .vue,.js", 10 | "prettier": "prettier --write .", 11 | "zip": "node zip.mjs" 12 | }, 13 | "engines": { 14 | "node": ">=20.0.0" 15 | }, 16 | "dependencies": { 17 | "archiver": "7.0.1", 18 | "axios": "1.11.0", 19 | "dayjs": "1.11.3", 20 | "element-plus": "2.9.9", 21 | "js-cookie": "3.0.5", 22 | "node-forge": "1.3.1", 23 | "nuxt": "3.17.2", 24 | "qrcode": "1.5.3", 25 | "vue": "3.5.20", 26 | "vue-router": "4.5.1" 27 | }, 28 | "devDependencies": { 29 | "@element-plus/nuxt": "1.0.8", 30 | "@nuxt/eslint-config": "1.3.0", 31 | "@vueuse/nuxt": "10.9.0", 32 | "eslint": "9.26.0", 33 | "eslint-config-prettier": "10.1.2", 34 | "eslint-plugin-prettier": "5.4.0", 35 | "eslint-plugin-vue": "10.1.0", 36 | "prettier": "3.2.5", 37 | "sass": "1.75.0", 38 | "terser": "5.31.0", 39 | "vite": "6.3.4" 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /assets/svg/phone.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /pages/lecturer/list.vue: -------------------------------------------------------------------------------- 1 | 14 | 35 | 40 | -------------------------------------------------------------------------------- /assets/svg/account/mobile.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /api/user.js: -------------------------------------------------------------------------------- 1 | import { getRequest, postRequest, putRequest } from '@/utils/request' 2 | 3 | export const userApi = { 4 | // 我的课程 5 | userCoursePage: (params = {}) => { 6 | return postRequest('/course/auth/user/course/page', params) 7 | }, 8 | 9 | // 我的订单 10 | orderPage: (params = {}) => { 11 | return postRequest('/user/auth/order/info/page', params) 12 | }, 13 | 14 | // 继续支付 15 | continuePay: (params = {}) => { 16 | return postRequest('/user/auth/order/pay/continue', params) 17 | }, 18 | 19 | // 取消支付 20 | cancelOrder: (params = {}) => { 21 | return putRequest('/user/auth/order/pay/cancel', params) 22 | }, 23 | 24 | // 用户信息修改 25 | usersUpdate: (params = {}) => { 26 | return postRequest('/user/auth/users/edit', params) 27 | }, 28 | 29 | // 用户信息 30 | getUserInfo: () => { 31 | return getRequest('/user/auth/users/view') 32 | }, 33 | 34 | // 用户绑定微信 35 | userBinding: (params = {}) => { 36 | return postRequest('/user/auth/users/binding', params) 37 | }, 38 | 39 | // 用户解绑微信 40 | userUnbind: () => { 41 | return getRequest('/user/auth/users/unbind') 42 | }, 43 | 44 | // 课程收藏列出 45 | userCourseCollectPage: (params = {}) => { 46 | return postRequest('/course/auth/user/course/collect/page', params) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /assets/svg/comment.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /utils/table.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 表单封装 3 | */ 4 | import { onMounted, reactive } from 'vue' 5 | 6 | export default function useTable(apis, paras = {}) { 7 | // 分页对象 8 | const page = reactive({ 9 | pageCurrent: 1, 10 | pageSize: 20, 11 | totalCount: 0, 12 | list: [], 13 | loading: true 14 | }) 15 | 16 | // 分页查询 17 | const handlePage = async () => { 18 | if (apis.page) { 19 | page.loading = true 20 | try { 21 | const res = await apis.page({ 22 | pageCurrent: page.pageCurrent, 23 | pageSize: page.pageSize, 24 | ...paras, 25 | ...query 26 | }) 27 | if (res) { 28 | page.list = res.list || res || [] 29 | page.totalCount = res.totalCount || 0 30 | } 31 | } finally { 32 | page.loading = false 33 | } 34 | } 35 | } 36 | 37 | // 查询对象 38 | const query = reactive({}) 39 | 40 | // 查询 41 | const handleQuery = () => { 42 | page.pageCurrent = 1 43 | // 分页查询 44 | handlePage().then(() => { 45 | //ElMessage.success('查询成功') 46 | }) 47 | } 48 | 49 | // 重置 50 | const resetQuery = () => { 51 | for (let i in query) { 52 | query[i] = '' 53 | } 54 | handleQuery() 55 | } 56 | 57 | // 获取数据 58 | onMounted(handlePage) 59 | 60 | return { 61 | page, 62 | handlePage, 63 | query, 64 | handleQuery, 65 | resetQuery 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /components/Course/Collect.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 47 | 48 | 63 | -------------------------------------------------------------------------------- /components/Common/Affix.vue: -------------------------------------------------------------------------------- 1 | 33 | 34 | 50 | -------------------------------------------------------------------------------- /components/Common/Link.vue: -------------------------------------------------------------------------------- 1 | 11 | 26 | 60 | -------------------------------------------------------------------------------- /components/Lecturer/List.vue: -------------------------------------------------------------------------------- 1 | 16 | 24 | 54 | -------------------------------------------------------------------------------- /components/Zone/Course.vue: -------------------------------------------------------------------------------- 1 | 16 | 24 | 56 | -------------------------------------------------------------------------------- /api/course.js: -------------------------------------------------------------------------------- 1 | import { getRequest, postRequest } from '@/utils/request' 2 | 3 | export const courseApi = { 4 | categoryList: () => { 5 | return getRequest('/course/api/category/list') 6 | }, 7 | 8 | // 课程列表(搜索) 9 | courseList: (params = {}) => { 10 | return postRequest('/course/api/course/search', params) 11 | }, 12 | 13 | // 课程详情 14 | courseDetail: (params = {}) => { 15 | return postRequest('/course/api/course/view', params) 16 | }, 17 | 18 | // 课程评论列出 19 | courseCommentPage: (params = {}) => { 20 | return postRequest('/course/api/course/comment', params) 21 | }, 22 | 23 | // 课程详情(登录后) 24 | userCourseDetail: (params = {}) => { 25 | return postRequest('/course/auth/course/view', params) 26 | }, 27 | 28 | // 获取播放sign 29 | studySign: (params = {}) => { 30 | return postRequest('/course/auth/course/sign', params) 31 | }, 32 | 33 | // 同步学习进度 34 | studyProgress: (params = {}) => { 35 | return postRequest('/course/api/user/study/progress', params) 36 | }, 37 | 38 | // 创建订单 39 | createOrder: (params = {}) => { 40 | return postRequest('/user/auth/order/pay/create', params) 41 | }, 42 | 43 | // 订单信息 44 | orderInfoView: (orderNo) => { 45 | return getRequest('/user/auth/order/info/view?orderNo=' + orderNo) 46 | }, 47 | 48 | // 课程评论添加 49 | courseCommentAdd: (params = {}) => { 50 | return postRequest('/course/auth/user/course/comment/add', params) 51 | }, 52 | 53 | // 课程收藏添加 54 | courseCollectAdd: (params = {}) => { 55 | return postRequest('/course/auth/user/course/collect/add', params) 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /utils/polyv.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 获取播放器实例 3 | */ 4 | export function getClient(playRes, speedDouble, speedDrag) { 5 | const params = JSON.parse(playRes.vodPlayConfig) 6 | 7 | // 当speed参数值为boolean类型时,代表是否显示倍速切换的按钮。当参数值为数组时,则代表倍速切换的可选速率。最多可设置6个速率,取值范围:(0,3]。PC端默认值为:[2, 1.5, 1.2, 0.5],移动端默认值为:[1, 1.5, 2]。 8 | const speed = speedDouble === 0 ? false : true 9 | // 是否禁止拖拽进度条,取值:{on,off}。 10 | const banSeek = speedDrag === 0 ? 'on' : 'off' 11 | 12 | return window.polyvPlayer({ 13 | wrap: '#player', 14 | height: '100%', 15 | width: '100%', 16 | autoplay: true, 17 | hideSwitchPlayer: true, 18 | showLine: 'off', 19 | history_video_duration: 1, 20 | speed: speed, 21 | ban_seek: banSeek, 22 | watchStartTime: playRes.currentDuration, 23 | playsafe: params.token, 24 | ...params 25 | }) 26 | } 27 | 28 | /** 29 | * 获取播放器实例(这里领课云使用保利威播放器,因为领课云使用的是标准的视频播放格式,支持通用的播放器) 30 | * @param playRes 31 | * @param speedDouble 32 | * @param speedDrag 33 | * @returns {*} 34 | */ 35 | export function getClientForPri(playRes, speedDouble, speedDrag) { 36 | const params = JSON.parse(playRes.vodPlayConfig) 37 | 38 | // 当speed参数值为boolean类型时,代表是否显示倍速切换的按钮。当参数值为数组时,则代表倍速切换的可选速率。最多可设置6个速率,取值范围:(0,3]。PC端默认值为:[2, 1.5, 1.2, 0.5],移动端默认值为:[1, 1.5, 2]。 39 | const speed = speedDouble === 0 ? false : true 40 | // 是否禁止拖拽进度条,取值:{on,off}。 41 | const banSeek = speedDrag === 0 ? 'on' : 'off' 42 | 43 | return window.polyvPlayer({ 44 | wrap: '#player', 45 | height: '100%', 46 | width: '100%', 47 | hideSwitchPlayer: true, 48 | autoplay: false, 49 | showLine: 'off', 50 | url: params.hdUrl, 51 | speed: speed, 52 | ban_seek: banSeek, 53 | watchStartTime: playRes.currentDuration 54 | }) 55 | } 56 | -------------------------------------------------------------------------------- /components/Common/Pagination.vue: -------------------------------------------------------------------------------- 1 | 2 | 15 | 65 | -------------------------------------------------------------------------------- /assets/svg/gzh.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/svg/chapter.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /components/Common/User.vue: -------------------------------------------------------------------------------- 1 | 28 | 49 | 55 | -------------------------------------------------------------------------------- /distribution/assembly.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | ${project.version} 19 | true 20 | 21 | dir 22 | 23 | tar.gz 24 | 25 | 26 | 27 | ${project.basedir}/bin 28 | bin 29 | 0755 30 | 0755 31 | 32 | 33 | ${project.basedir}/../.output 34 | 35 | 36 | ${project.basedir}/../node_modules 37 | 38 | 39 | 40 | 41 | ${project.basedir}/../nuxt.config.ts 42 | 43 | 44 | ${project.basedir}/../ecosystem.config.js 45 | 46 | 47 | ${project.basedir}/../package.json 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /assets/svg/account/wechat.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /utils/storage.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 存储localStorage 3 | * @param expireTime 单位:分 4 | */ 5 | export function setStorage(name, content, expireTime) { 6 | if (!name) return 7 | let params = JSON.stringify(content) 8 | if (expireTime) { 9 | expireTime = Date.now() + expireTime * 1000 * 60 10 | params = JSON.stringify({ content: content, expireTime: expireTime }) 11 | } 12 | window.localStorage.setItem(name, params) 13 | } 14 | 15 | /** 16 | * 获取localStorage 17 | */ 18 | export function getStorage(name) { 19 | if (!name) return 20 | let data = window.localStorage.getItem(name) 21 | if (!data) return null 22 | data = JSON.parse(data) 23 | if (data) { 24 | if (data.expireTime && data.expireTime > 0) { 25 | if (data.expireTime > Date.now()) { 26 | return data.content 27 | } 28 | window.localStorage.removeItem(name) 29 | return null 30 | } 31 | return data 32 | } 33 | return null 34 | } 35 | 36 | /** 37 | * 38 | * @param name 39 | * @param expireTime 单位:分 40 | */ 41 | export function setSessionStorage(name, content, expireTime) { 42 | if (!name) return 43 | let params = JSON.stringify(content) 44 | if (expireTime) { 45 | expireTime = Date.now() + expireTime * 1000 * 60 46 | params = JSON.stringify({ content: content, expireTime: expireTime }) 47 | } 48 | window.sessionStorage.setItem(name, params) 49 | } 50 | 51 | /** 52 | * 获取sessionStorage 53 | */ 54 | export function getSessionStorage(name) { 55 | if (!name) return null 56 | let data = window.sessionStorage.getItem(name) 57 | if (!data) return null 58 | data = JSON.parse(data) 59 | if (data) { 60 | if (data.expireTime && data.expireTime > 0) { 61 | if (data.expireTime > Date.now()) { 62 | return data.content 63 | } 64 | window.sessionStorage.removeItem(name) 65 | return null 66 | } 67 | return data 68 | } 69 | return null 70 | } 71 | -------------------------------------------------------------------------------- /components/Account/Wechat.vue: -------------------------------------------------------------------------------- 1 |