├── .prettierignore
├── public
└── favicon.ico
├── src
├── assets
│ ├── images
│ │ ├── logo.png
│ │ ├── weixin.jpg
│ │ ├── weixin.png
│ │ ├── common
│ │ │ ├── 403.png
│ │ │ ├── 404.png
│ │ │ └── beian.png
│ │ ├── check.svg
│ │ ├── folder.svg
│ │ └── logo.svg
│ ├── svg
│ │ ├── 课程.svg
│ │ ├── 装修.svg
│ │ ├── 用户.svg
│ │ ├── 概况.svg
│ │ ├── 系统.svg
│ │ └── 常用.svg
│ └── styles
│ │ └── index.scss
├── store
│ ├── index.js
│ └── modules
│ │ ├── website.js
│ │ ├── upload.js
│ │ └── user.js
├── utils
│ ├── bus.js
│ ├── constants
│ │ └── system.js
│ ├── permission.js
│ ├── cookie.js
│ ├── storage.js
│ ├── vod
│ │ ├── simple.js
│ │ └── polyv.js
│ ├── base.js
│ └── table.js
├── api
│ ├── dashboard.js
│ ├── login.js
│ ├── upload.js
│ └── users.js
├── App.vue
├── views
│ ├── 404.vue
│ ├── 403.vue
│ ├── system
│ │ ├── config
│ │ │ ├── View.vue
│ │ │ └── index.vue
│ │ ├── log
│ │ │ ├── LogView.vue
│ │ │ └── index.vue
│ │ ├── role
│ │ │ ├── RoleForm.vue
│ │ │ ├── MenuSet.vue
│ │ │ └── index.vue
│ │ ├── user
│ │ │ ├── Password.vue
│ │ │ ├── RoleSet.vue
│ │ │ └── UserForm.vue
│ │ └── app
│ │ │ ├── index.vue
│ │ │ └── AppForm.vue
│ ├── dashboard
│ │ ├── StatLogin.vue
│ │ ├── index.vue
│ │ └── StatData.vue
│ ├── course
│ │ ├── record
│ │ │ ├── Collect.vue
│ │ │ ├── Study.vue
│ │ │ ├── Comment.vue
│ │ │ ├── Course.vue
│ │ │ ├── index.vue
│ │ │ └── Order.vue
│ │ ├── chapter
│ │ │ ├── ChapterForm.vue
│ │ │ └── PeriodForm.vue
│ │ ├── resource
│ │ │ ├── ResourceForm.vue
│ │ │ └── MoveModel.vue
│ │ └── category
│ │ │ ├── CategoryForm.vue
│ │ │ └── index.vue
│ ├── users
│ │ ├── record
│ │ │ ├── Study.vue
│ │ │ ├── Account.vue
│ │ │ ├── Course.vue
│ │ │ ├── ConsumeForm.vue
│ │ │ ├── index.vue
│ │ │ └── Order.vue
│ │ ├── log
│ │ │ └── index.vue
│ │ ├── list
│ │ │ └── UsersForm.vue
│ │ └── lecturer
│ │ │ ├── LecturerForm.vue
│ │ │ └── index.vue
│ └── common
│ │ ├── order
│ │ └── OrderForm.vue
│ │ ├── navigation
│ │ ├── NavigationForm.vue
│ │ └── index.vue
│ │ ├── zone
│ │ └── ZoneForm.vue
│ │ ├── link
│ │ ├── LinkForm.vue
│ │ └── index.vue
│ │ └── carousel
│ │ └── CarouselForm.vue
├── layout
│ ├── components
│ │ ├── Navbar
│ │ │ ├── Logo.vue
│ │ │ ├── index.vue
│ │ │ ├── Breadcrumb.vue
│ │ │ └── User.vue
│ │ └── Mains.vue
│ └── index.vue
├── components
│ ├── Enum
│ │ ├── View
│ │ │ └── index.vue
│ │ ├── Radio
│ │ │ └── index.vue
│ │ └── Select
│ │ │ └── index.vue
│ ├── Cascader
│ │ ├── Course
│ │ │ └── index.vue
│ │ └── Category
│ │ │ └── CategoryForm.vue
│ ├── Icon
│ │ └── index.vue
│ ├── Editor
│ │ ├── index.js
│ │ ├── Custom
│ │ │ └── image.js
│ │ └── index.vue
│ ├── Selector
│ │ ├── Svg
│ │ │ └── index.vue
│ │ ├── Lecturer
│ │ │ └── index.vue
│ │ ├── Image
│ │ │ └── index.vue
│ │ └── Course
│ │ │ └── index.vue
│ ├── Upload
│ │ ├── App
│ │ │ └── index.vue
│ │ └── File
│ │ │ └── index.vue
│ ├── Pagination
│ │ └── index.vue
│ └── Preview
│ │ └── index.vue
├── main.js
└── router
│ └── index.js
├── distribution
├── images
│ ├── gzh.png
│ ├── logo.jpg
│ ├── web1.png
│ ├── web2.png
│ ├── web3.png
│ ├── web4.png
│ ├── admin1.png
│ ├── admin2.png
│ ├── admin3.png
│ └── admin4.png
├── assembly.xml
└── pom.xml
├── jsconfig.json
├── .prettierrc.json
├── .gitignore
├── eslint.config.js
├── zip.mjs
├── index.html
├── LICENSE.txt
├── vite.config.js
├── package.json
└── README.md
/.prettierignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | dist
3 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/roncoo/roncoo-education-admin/HEAD/public/favicon.ico
--------------------------------------------------------------------------------
/src/assets/images/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/roncoo/roncoo-education-admin/HEAD/src/assets/images/logo.png
--------------------------------------------------------------------------------
/distribution/images/gzh.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/roncoo/roncoo-education-admin/HEAD/distribution/images/gzh.png
--------------------------------------------------------------------------------
/distribution/images/logo.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/roncoo/roncoo-education-admin/HEAD/distribution/images/logo.jpg
--------------------------------------------------------------------------------
/distribution/images/web1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/roncoo/roncoo-education-admin/HEAD/distribution/images/web1.png
--------------------------------------------------------------------------------
/distribution/images/web2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/roncoo/roncoo-education-admin/HEAD/distribution/images/web2.png
--------------------------------------------------------------------------------
/distribution/images/web3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/roncoo/roncoo-education-admin/HEAD/distribution/images/web3.png
--------------------------------------------------------------------------------
/distribution/images/web4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/roncoo/roncoo-education-admin/HEAD/distribution/images/web4.png
--------------------------------------------------------------------------------
/src/assets/images/weixin.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/roncoo/roncoo-education-admin/HEAD/src/assets/images/weixin.jpg
--------------------------------------------------------------------------------
/src/assets/images/weixin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/roncoo/roncoo-education-admin/HEAD/src/assets/images/weixin.png
--------------------------------------------------------------------------------
/src/store/index.js:
--------------------------------------------------------------------------------
1 | import { createPinia } from 'pinia'
2 |
3 | const store = createPinia()
4 | export default store
5 |
--------------------------------------------------------------------------------
/distribution/images/admin1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/roncoo/roncoo-education-admin/HEAD/distribution/images/admin1.png
--------------------------------------------------------------------------------
/distribution/images/admin2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/roncoo/roncoo-education-admin/HEAD/distribution/images/admin2.png
--------------------------------------------------------------------------------
/distribution/images/admin3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/roncoo/roncoo-education-admin/HEAD/distribution/images/admin3.png
--------------------------------------------------------------------------------
/distribution/images/admin4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/roncoo/roncoo-education-admin/HEAD/distribution/images/admin4.png
--------------------------------------------------------------------------------
/src/utils/bus.js:
--------------------------------------------------------------------------------
1 | import mitt from 'mitt'
2 |
3 | /**
4 | * 创建一个事务总线
5 | */
6 | const bus = mitt()
7 | export default bus
8 |
--------------------------------------------------------------------------------
/src/assets/images/common/403.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/roncoo/roncoo-education-admin/HEAD/src/assets/images/common/403.png
--------------------------------------------------------------------------------
/src/assets/images/common/404.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/roncoo/roncoo-education-admin/HEAD/src/assets/images/common/404.png
--------------------------------------------------------------------------------
/src/assets/images/common/beian.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/roncoo/roncoo-education-admin/HEAD/src/assets/images/common/beian.png
--------------------------------------------------------------------------------
/jsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ESNext",
4 | "module": "ESNext",
5 | "baseUrl": ".",
6 | "paths": {
7 | "@/*": ["src/*"]
8 | }
9 | },
10 | "include": ["src/**/*.vue", "src/**/*"]
11 | }
12 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/src/utils/constants/system.js:
--------------------------------------------------------------------------------
1 | /*
2 | * 通用常量
3 | */
4 | export const PATH = {
5 | URL_LOGIN: '/login',
6 | URL_404: '/404',
7 | URL_403: '/403',
8 | URL_GATEWAY: '/gateway',
9 | URL_DASHBOARD: '/dashboard'
10 | }
11 | export const TOKEN_KEY = 'EDU_OS_ADMIN_TOKEN'
12 |
--------------------------------------------------------------------------------
/src/utils/permission.js:
--------------------------------------------------------------------------------
1 | import { useUserStore } from '@/store/modules/user.js'
2 |
3 | export function hasPermission(keyValue) {
4 | const permissions = useUserStore().getPermissionList
5 | if (!permissions?.includes(keyValue)) {
6 | return false
7 | }
8 | return true
9 | }
10 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | dist
3 | npm-debug.log*
4 | yarn-debug.log*
5 |
6 | .DS_Store
7 | .idea
8 | .vscode
9 | *.suo
10 | *.ntvs*
11 | *.njsproj
12 | *.sln
13 |
14 | *.classpath
15 | *.project
16 | *.settings
17 | *.mvn
18 | *.springBeans
19 | *.factorypath
20 |
21 | package-lock.json
22 | pnpm-lock.yaml
--------------------------------------------------------------------------------
/src/api/dashboard.js:
--------------------------------------------------------------------------------
1 | import { getRequest } from '@/utils/request'
2 |
3 | export const statApi = {
4 | // 数据统计
5 | data: () => {
6 | return getRequest('/user/admin/stat/data')
7 | },
8 | // 用户注册登录统计
9 | login: () => {
10 | return getRequest('/user/admin/stat/login?dates=-14')
11 | },
12 | // 点播用量统计
13 | vod: () => {
14 | return getRequest('/system/admin/stat/vod')
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
14 |
--------------------------------------------------------------------------------
/eslint.config.js:
--------------------------------------------------------------------------------
1 | import js from '@eslint/js'
2 | import globals from 'globals'
3 | import pluginVue from 'eslint-plugin-vue'
4 | import { defineConfig } from 'eslint/config'
5 |
6 | export default defineConfig([
7 | { files: ['**/*.{js,mjs,cjs,vue}'], plugins: { js }, extends: ['js/recommended'] },
8 | { files: ['**/*.{js,mjs,cjs,vue}'], languageOptions: { globals: globals.browser } },
9 | pluginVue.configs['flat/essential']
10 | ])
11 |
--------------------------------------------------------------------------------
/zip.mjs:
--------------------------------------------------------------------------------
1 | /**
2 | * 打包工具,方便将打包后的dist进行管理,打包后的文件为:admin.zip
3 | */
4 | import { createWriteStream } from 'fs'
5 | import path from 'path'
6 | import archiver from 'archiver'
7 |
8 | const output = createWriteStream(path.resolve('./admin.zip'))
9 | const archive = archiver('zip', { zlib: { level: 9 } })
10 |
11 | archive.pipe(output)
12 | archive.directory(path.resolve('dist'), '', null)
13 | archive.finalize().then(() => {
14 | console.log('打包成功,请查看根目录下的:admin.zip')
15 | })
16 |
--------------------------------------------------------------------------------
/src/api/login.js:
--------------------------------------------------------------------------------
1 | import { getRequest, postRequest } from '@/utils/request'
2 |
3 | export const loginApi = {
4 | getWebsite: () => {
5 | return getRequest('/system/api/sys/config/website')
6 | },
7 | getCodeImg: () => {
8 | return getRequest('/system/api/common/code')
9 | },
10 | login: (data) => {
11 | return postRequest('/system/admin/login/password', data)
12 | },
13 | getUserInfo: () => {
14 | return getRequest('/system/admin/sys/user/current')
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/views/404.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 返回首页
5 |
6 |
7 |
8 |
18 |
--------------------------------------------------------------------------------
/src/store/modules/website.js:
--------------------------------------------------------------------------------
1 | import { defineStore } from 'pinia'
2 | import { loginApi } from '@/api/login.js'
3 |
4 | export const useWebsiteStore = defineStore({
5 | id: 'website',
6 | state: () => ({
7 | info: {}
8 | }),
9 | getters: {
10 | getInfo(state) {
11 | return state.info
12 | }
13 | },
14 | actions: {
15 | // 登录操作
16 | init() {
17 | loginApi.getWebsite().then((res) => {
18 | this.info = res
19 | })
20 | }
21 | }
22 | })
23 |
--------------------------------------------------------------------------------
/src/views/403.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 返回首页
5 |
6 |
7 |
8 |
18 |
--------------------------------------------------------------------------------
/src/utils/cookie.js:
--------------------------------------------------------------------------------
1 | import Cookies from 'js-cookie'
2 | import { TOKEN_KEY } from '@/utils/constants/system'
3 |
4 | /**
5 | * 单位:天
6 | */
7 | const TokenExpiresTime = 1
8 |
9 | export function setToken(token) {
10 | return Cookies.set(TOKEN_KEY, token, {
11 | expires: TokenExpiresTime
12 | })
13 | }
14 |
15 | export function getToken() {
16 | return Cookies.get(TOKEN_KEY)
17 | }
18 |
19 | export function removeToken() {
20 | return Cookies.remove(TOKEN_KEY, {
21 | expires: 0
22 | })
23 | }
24 |
--------------------------------------------------------------------------------
/src/assets/images/check.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/src/layout/components/Navbar/Logo.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |

4 |
5 |
6 |
7 |
8 |
25 |
--------------------------------------------------------------------------------
/src/layout/components/Navbar/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
13 |
14 |
24 |
--------------------------------------------------------------------------------
/src/layout/components/Mains.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
27 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | 运营管理后台
9 |
10 |
11 |
12 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/src/components/Enum/View/index.vue:
--------------------------------------------------------------------------------
1 |
2 | {{ enumVal }}
3 |
4 |
5 |
28 |
--------------------------------------------------------------------------------
/src/api/upload.js:
--------------------------------------------------------------------------------
1 | import { getRequest, postRequest, upload } from '@/utils/request'
2 |
3 | export const uploadApi = {
4 | pic: (file) => {
5 | return upload('/system/admin/upload/pic?name=' + file.name, file, 'picFile')
6 | },
7 | doc: (file, cb, cancelFun) => {
8 | return upload('/system/admin/upload/doc?name=' + file.name, file, 'docFile', cb, cancelFun)
9 | },
10 | app: (file, cb, cancelFun) => {
11 | return upload('/system/admin/upload/app?name=' + file.name, file, 'appFile', cb, cancelFun)
12 | },
13 | getVodConfig: () => {
14 | return getRequest('/course/admin/resource/vod/config?t' + Date.now())
15 | },
16 | saveResource: (data) => {
17 | return postRequest('/course/admin/resource/save?t=' + Date.now(), data)
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/components/Cascader/Course/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
28 |
--------------------------------------------------------------------------------
/src/layout/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
24 |
33 |
--------------------------------------------------------------------------------
/src/store/modules/upload.js:
--------------------------------------------------------------------------------
1 | import { defineStore } from 'pinia'
2 |
3 | export const useUploadStore = defineStore({
4 | id: 'upload',
5 | state: () => ({
6 | fileList: [],
7 | successFileList: []
8 | }),
9 | getters: {
10 | getFileList(state) {
11 | return state.fileList
12 | },
13 | getSuccessFileList(state) {
14 | return state.successFileList
15 | }
16 | },
17 | actions: {
18 | // 添加文件
19 | addFile(data) {
20 | this.fileList.push(data)
21 | },
22 | addSuccessFile(data) {
23 | this.successFileList.push(data)
24 | },
25 | // 清空文件
26 | clearFile() {
27 | this.fileList.splice(0, this.fileList.length)
28 | },
29 | clearSuccessFile() {
30 | this.successFileList.splice(0, this.successFileList.length)
31 | }
32 | }
33 | })
34 |
--------------------------------------------------------------------------------
/src/components/Icon/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
29 |
30 |
40 |
--------------------------------------------------------------------------------
/src/components/Editor/index.js:
--------------------------------------------------------------------------------
1 | import { Boot } from '@wangeditor/editor'
2 | import ImageMenu from './Custom/image.js'
3 |
4 | const MenusList = [
5 | {
6 | index: 20,
7 | key: 'ImageMenu',
8 | class: ImageMenu
9 | }
10 | ]
11 |
12 | const registerMenu = function (editor, toolbarConfig) {
13 | const allRegisterMenu = editor.getAllMenuKeys() // 获取所有已注册的菜单
14 | let keys = []
15 | for (let item of MenusList) {
16 | if (allRegisterMenu.indexOf(item.key) < 0) {
17 | // 如果未注册,则注册
18 | const menuObj = {
19 | key: item.key,
20 | factory() {
21 | return new item.class()
22 | }
23 | }
24 | Boot.registerMenu(menuObj)
25 | }
26 | keys.push(item.key)
27 | }
28 | toolbarConfig.insertKeys = {
29 | index: MenusList[0].index,
30 | keys: keys
31 | }
32 | }
33 |
34 | export default registerMenu
35 |
--------------------------------------------------------------------------------
/src/components/Enum/Radio/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{ item.desc }}
4 |
5 |
6 |
7 |
30 |
--------------------------------------------------------------------------------
/src/layout/components/Navbar/Breadcrumb.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{ item.title }}
4 |
5 |
6 |
7 |
23 |
24 |
33 |
--------------------------------------------------------------------------------
/src/views/system/config/View.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
10 |
11 |
12 |
13 |
35 |
--------------------------------------------------------------------------------
/src/components/Enum/Select/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
34 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/vite.config.js:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite'
2 | import { resolve } from 'path'
3 | import vue from '@vitejs/plugin-vue'
4 | import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'
5 |
6 | export default defineConfig({
7 | base: './',
8 | telemetry: false,
9 | server: {
10 | port: 9528, // 服务启动端口号
11 | open: true, // 服务启动时是否自动打开浏览器
12 | proxy: {
13 | '/gateway': {
14 | target: 'http://localhost:7700',
15 | changeOrigin: true,
16 | rewrite: (path) => path.replace(/^\/gateway/, '')
17 | }
18 | }
19 | },
20 | resolve: {
21 | alias: {
22 | '@': resolve(__dirname, '.', 'src')
23 | }
24 | },
25 | plugins: [
26 | vue(),
27 | createSvgIconsPlugin({
28 | iconDirs: [resolve(process.cwd(), 'src/assets/svg')],
29 | symbolId: 'icon-[name]'
30 | })
31 | ],
32 | build: {
33 | minify: 'terser',
34 | emptyOutDir: true,
35 | chunkSizeWarningLimit: 1500,
36 | terserOptions: {
37 | compress: {
38 | drop_console: true,
39 | drop_debugger: true
40 | }
41 | }
42 | }
43 | })
44 |
--------------------------------------------------------------------------------
/src/assets/images/folder.svg:
--------------------------------------------------------------------------------
1 |
13 |
--------------------------------------------------------------------------------
/distribution/assembly.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 | ${project.version}
19 | true
20 |
21 |
22 |
23 | tar.gz
24 |
25 |
26 |
27 | ${project.basedir}/../dist
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/src/assets/svg/课程.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/src/views/system/log/LogView.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
9 |
10 |
11 |
12 |
42 |
--------------------------------------------------------------------------------
/src/assets/styles/index.scss:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | word-break: break-all;
4 | }
5 |
6 | a {
7 | text-decoration: none;
8 | color: inherit;
9 | }
10 |
11 | .c-danger {
12 | color: gray;
13 | }
14 |
15 | .c-special {
16 | color: red;
17 | font-weight: bold;
18 | }
19 |
20 | .search_bar {
21 | text-align: left;
22 | }
23 |
24 | .button_bar {
25 | text-align: left;
26 | margin-bottom: 10px;
27 | }
28 |
29 | // 编辑器全屏
30 | .w-e-full-screen-container {
31 | z-index: 9999;
32 | }
33 |
34 | // 文字提示
35 | .tip-info {
36 | margin-left: 5px;
37 | font-size: 12px;
38 | }
39 |
40 | // 弹窗
41 | .el-dialog__body {
42 | max-height: 80vh;
43 | overflow: auto;
44 | padding: 0 20px;
45 | }
46 |
47 | // 分页组件
48 | .el-pagination {
49 | margin-top: 20px;
50 | justify-content: center;
51 | }
52 |
53 | // 表头样式
54 | .el-table .el-table__header th.is-leaf {
55 | background-color: #f9f9f9;
56 | height: 50px;
57 | }
58 |
59 | .el-tree-node__content {
60 | height: 40px;
61 | }
62 |
63 | .el-divider--vertical {
64 | margin: 0;
65 | }
66 |
67 | // 滚动条样式
68 | ::-webkit-scrollbar {
69 | width: 5px;
70 | height: 5px;
71 | border-radius: 5px;
72 | }
73 |
74 | ::-webkit-scrollbar-thumb {
75 | border-radius: 5px;
76 | background: rgba(0, 0, 0, 0.2);
77 | }
78 |
79 | ::-webkit-scrollbar-track {
80 | border-radius: 0;
81 | background: #fff;
82 | }
83 |
--------------------------------------------------------------------------------
/src/components/Editor/Custom/image.js:
--------------------------------------------------------------------------------
1 | export default class ImageMenu {
2 | constructor() {
3 | this.title = '选择图片' // 自定义菜单标题
4 | this.iconSvg =
5 | '' // 可选
6 | this.tag = 'button'
7 | }
8 |
9 | // 获取菜单执行时的 value ,用不到则返回空 字符串或 false
10 | getValue(editor) {
11 | return ''
12 | }
13 |
14 | // 菜单是否需要激活(如选中加粗文本,“加粗”菜单会激活),用不到则返回 false
15 | isActive(editor) {
16 | return false
17 | }
18 |
19 | // 菜单是否需要禁用(如选中 H1 ,“引用”菜单被禁用),用不到则返回 false
20 | isDisabled(editor) {
21 | return false
22 | }
23 |
24 | // 点击菜单时触发的函数
25 | exec(editor, value) {
26 | if (this.isDisabled(editor)) return
27 | editor.emit('PicMenuClick', value)
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/utils/storage.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 存储localStorage
3 | */
4 | export function setStore(name, content) {
5 | if (!name) return
6 | if (typeof content !== 'string') {
7 | content = JSON.stringify(content)
8 | }
9 | window.localStorage.setItem(name, content)
10 | }
11 |
12 | /**
13 | * 获取localStorage
14 | */
15 | export function getStore(name) {
16 | if (!name) return
17 | return window.localStorage.getItem(name)
18 | }
19 |
20 | /**
21 | *
22 | * @param name
23 | * @param content
24 | * @param expireTime 单位:分
25 | */
26 | export function setSessionStorage(name, content, expireTime) {
27 | if (!name) return
28 | let params = JSON.stringify(content)
29 | if (expireTime) {
30 | expireTime = Date.now() + expireTime * 1000 * 60
31 | params = JSON.stringify({ content: content, expireTime: expireTime })
32 | }
33 | window.sessionStorage.setItem(name, params)
34 | }
35 |
36 | /**
37 | * 获取sessionStorage
38 | */
39 | export function getSessionStorage(name) {
40 | if (!name) return null
41 | let data = window.sessionStorage.getItem(name)
42 | if (!data) return null
43 | data = JSON.parse(data)
44 | if (data) {
45 | if (data.expireTime && data.expireTime > 0) {
46 | if (data.expireTime > Date.now()) {
47 | return data.content
48 | }
49 | window.sessionStorage.removeItem(name)
50 | return null
51 | }
52 | return data
53 | }
54 | return null
55 | }
56 |
--------------------------------------------------------------------------------
/src/views/dashboard/StatLogin.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | 最近14天人数统计
4 |
5 |
6 |
7 |
8 |
54 |
64 |
--------------------------------------------------------------------------------
/src/components/Selector/Svg/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
{{ item }}
5 |
6 |
7 |
8 |
9 |
34 |
35 |
53 |
--------------------------------------------------------------------------------
/src/assets/svg/装修.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/views/system/config/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
58 |
64 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "roncoo-education-admin",
3 | "version": "25.0.0-RELEASE",
4 | "license": "MIT",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "vite build",
9 | "serve": "vite preview",
10 | "lint": "eslint src --fix --ext .ts,.tsx,.vue,.js,.jsx",
11 | "prettier": "prettier --write src",
12 | "zip": "node zip.mjs"
13 | },
14 | "engines": {
15 | "node": ">=20.0.0"
16 | },
17 | "dependencies": {
18 | "@element-plus/icons-vue": "2.3.1",
19 | "@polyv/vod-upload-js-sdk": "1.6.0",
20 | "@wangeditor/editor": "5.1.23",
21 | "@wangeditor/editor-for-vue": "5.1.12",
22 | "archiver": "7.0.1",
23 | "axios": "1.11.0",
24 | "echarts": "5.5.0",
25 | "element-plus": "2.9.9",
26 | "js-cookie": "3.0.5",
27 | "jsencrypt": "3.2.1",
28 | "lodash": "4.17.21",
29 | "mitt": "3.0.1",
30 | "pinia": "2.1.7",
31 | "simple-uploader.js": "0.6.0",
32 | "sortablejs": "1.15.2",
33 | "vue": "3.5.20",
34 | "vue-json-pretty": "2.5.0",
35 | "vue-router": "4.5.1",
36 | "vuedraggable": "4.1.0"
37 | },
38 | "devDependencies": {
39 | "@eslint/js": "9.34.0",
40 | "@vitejs/plugin-vue": "5.0.4",
41 | "eslint": "9.26.0",
42 | "eslint-config-prettier": "10.1.2",
43 | "eslint-plugin-prettier": "5.4.0",
44 | "eslint-plugin-vue": "10.1.0",
45 | "fast-glob": "3.3.3",
46 | "globals": "16.3.0",
47 | "prettier": "3.2.5",
48 | "sass": "1.75.0",
49 | "terser": "5.31.0",
50 | "vite": "6.3.4",
51 | "vite-plugin-svg-icons": "2.0.1"
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/components/Upload/App/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | 上传
4 |
5 | 处理中
6 | 成功
7 |
8 |
9 |
10 |
48 |
49 |
54 |
--------------------------------------------------------------------------------
/src/views/course/record/Collect.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | 查询
11 | 重置
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
39 |
--------------------------------------------------------------------------------
/distribution/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | com.roncoo
8 | distribution
9 | 25.0.0-RELEASE
10 | pom
11 | distribution
12 |
13 |
14 |
15 | release-education
16 |
17 | true
18 |
19 |
20 |
21 |
22 | org.apache.maven.plugins
23 | maven-assembly-plugin
24 | 3.0.0
25 |
26 | false
27 |
28 | assembly.xml
29 |
30 |
31 |
32 |
33 | make-assembly
34 | package
35 |
36 | single
37 |
38 |
39 |
40 |
41 |
42 | admin
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/src/views/dashboard/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | 特别说明
10 |
11 |
12 |
1. 演示环境仅有查看功能,更多体验需本地部署
13 |
2. 系统如何搭建部署?视频如何实现本地私有化?
14 |
3. 作者提供有偿服务:18302045627(微信同号)
15 |
4. 关注公众号,获取更多资料:SQL脚本、教程
16 |
17 |

18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
37 |
54 |
--------------------------------------------------------------------------------
/src/main.js:
--------------------------------------------------------------------------------
1 | import { createApp } from 'vue'
2 | import ElementPlus from 'element-plus'
3 | import 'element-plus/dist/index.css'
4 | import '@/assets/styles/index.scss'
5 | import App from '@/App.vue'
6 | import router, { createNewRouter } from '@/router/index.js'
7 | import store from '@/store/index.js'
8 | import { getToken } from '@/utils/cookie.js'
9 | import { loginApi } from '@/api/login.js'
10 | import { useUserStore } from '@/store/modules/user.js'
11 | import * as ElementPlusIconsVue from '@element-plus/icons-vue'
12 | import 'virtual:svg-icons-register'
13 | import Icon from '@/components/Icon/index.vue'
14 | import { hasPermission } from '@/utils/permission.js'
15 |
16 | // 初始化
17 | setupInit()
18 |
19 | async function setupInit() {
20 | if (!getToken()) {
21 | // 用户没登录
22 | init()
23 | } else {
24 | // 用户已登录
25 | const res = await loginApi.getUserInfo()
26 | // 创建动态路由
27 | createNewRouter(res.routerList)
28 | init()
29 | useUserStore().login(res)
30 | }
31 | }
32 |
33 | function init() {
34 | const app = createApp(App)
35 | app.use(router)
36 | app.use(store)
37 | app.use(ElementPlus)
38 |
39 | // 注册图标组件
40 | for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
41 | app.component(key, component)
42 | }
43 | // 注册图标组件
44 | app.component('Icon', Icon)
45 |
46 | // 注册自定义指令(权限使用)
47 | app.directive('permission', (el, binding) => {
48 | if (!hasPermission(binding.value)) {
49 | el.parentNode && el.parentNode.removeChild(el)
50 | }
51 | })
52 |
53 | // 全局配置:Dialog遮罩层点击不关闭
54 | app._context.components.ElDialog.props.closeOnClickModal.default = false
55 |
56 | // 挂载
57 | app.mount('#app')
58 | }
59 |
--------------------------------------------------------------------------------
/src/views/users/record/Study.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | {{ scope.row.chapterName }}
7 | {{ scope.row.periodName }}
8 |
9 |
10 |
11 |
12 | {{ scope.row.gmtCreate }}
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
44 |
--------------------------------------------------------------------------------
/src/components/Pagination/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
14 |
15 |
65 |
--------------------------------------------------------------------------------
/src/views/course/record/Study.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | {{ scope.row.chapterName }}
7 | {{ scope.row.periodName }}
8 |
9 |
10 |
11 |
12 | {{ scope.row.gmtCreate }}
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
44 |
--------------------------------------------------------------------------------
/src/utils/vod/simple.js:
--------------------------------------------------------------------------------
1 | // 分片上传
2 | import SimpleUploader from 'simple-uploader.js'
3 |
4 | export const getSimpleClient = (userData) => {
5 | const simpleClient = new SimpleUploader({
6 | target: userData.uploadUrl,
7 | chunkSize: '2048000', // 分片大小,单位bytes,这里为2M
8 | simultaneousUploads: 5, // 并发上传数,默认为3
9 | maxChunkRetries: 3, // 上传失败重试次数,默认为0
10 | progressCallbacksInterval: 1000, // 上传进度回调间隔,单位ms,默认为500ms
11 | testChunks: true, // 是否要测试分片是否完整,默认为true
12 | checkChunkUploadedByResponse: function (chunk, message) {
13 | try {
14 | const objMessage = JSON.parse(message)
15 | if (objMessage.code === 200 && objMessage.data?.uploadStatusId === 2) {
16 | return true
17 | } else {
18 | return false
19 | }
20 | } catch (error) {
21 | console.error(error)
22 | return false
23 | }
24 | },
25 | query: {
26 | isChunk: true,
27 | ...userData
28 | }
29 | })
30 | return simpleClient
31 | }
32 |
33 | export const uploadSimple = (simpleClient, startFile, callback) => {
34 | simpleClient.on('fileAdded', function (file) {
35 | startFile.status = 'uploading'
36 | callback('FileStarted', file)
37 | })
38 | simpleClient.on('fileProgress', function (rootFile, file, chunk) {
39 | const uploadInfo = {
40 | progress: file.progress()
41 | }
42 | callback('FileProgress', uploadInfo)
43 | })
44 | simpleClient.on('fileSuccess', function (rootFile, file, message, chunk) {
45 | const uploadInfo = {
46 | vid: JSON.parse(message).data.videoVid
47 | }
48 | callback('FileSucceed', uploadInfo)
49 | })
50 | simpleClient.on('fileError', function (rootFile, file, message) {
51 | callback('FileFailed', message)
52 | })
53 |
54 | simpleClient.addFile(startFile.file)
55 | simpleClient.upload()
56 | }
57 |
--------------------------------------------------------------------------------
/src/views/course/record/Comment.vue:
--------------------------------------------------------------------------------
1 |
2 |
28 |
29 |
45 |
--------------------------------------------------------------------------------
/src/utils/vod/polyv.js:
--------------------------------------------------------------------------------
1 | import PlvVideoUpload from '@polyv/vod-upload-js-sdk'
2 |
3 | export const getPolyvClient = (userData) => {
4 | //初始化上传实例
5 | const polyvClient = new PlvVideoUpload({
6 | region: 'auto',
7 | events: {
8 | Error: (err) => {
9 | // 错误事件回调
10 | console.error(err)
11 | },
12 | UploadComplete: () => {
13 | // 全部上传任务完成回调
14 | }
15 | }
16 | })
17 | // 设置账号授权验证信息
18 | polyvClient.updateUserData({
19 | userid: userData.userid,
20 | ptime: userData.ptime,
21 | hash: userData.hash,
22 | sign: userData.sign,
23 | cataid: userData.categoryId
24 | })
25 | return polyvClient
26 | }
27 |
28 | export const uploadPolyv = (polyvClient, startFile, callback) => {
29 | // 添加文件到文件
30 | polyvClient.addFile(
31 | startFile.file,
32 | {
33 | FileStarted: function (uploadInfo) {
34 | // 文件开始上传回调
35 | startFile.status = 'uploading'
36 | callback('FileStarted', uploadInfo)
37 | },
38 | FileProgress: function (uploadInfo) {
39 | // 文件上传过程返回上传进度信息回调
40 | callback('FileProgress', uploadInfo)
41 | },
42 | FileStopped: function (uploadInfo) {
43 | // 文件暂停上传回调
44 | callback('FileStopped', uploadInfo)
45 | },
46 | FileSucceed: function (uploadInfo) {
47 | // 文件上传成功回调
48 | callback('FileSucceed', uploadInfo)
49 | },
50 | FileFailed: function (uploadInfo) {
51 | // 文件上传失败回调
52 | callback('FileFailed', uploadInfo)
53 | }
54 | },
55 | {
56 | // 文件上传相关信息设置
57 | //title: file.name, // 标题
58 | //desc: , // 描述
59 | //cataid: startFile.categoryId, // 上传分类目录ID
60 | //tag: , // 标签
61 | luping: 1, // 是否开启视频课件优化处理,对于上传录屏类视频清晰度有所优化:0为不开启,1为开启
62 | keepsource: 0 // 是否源文件播放(不对视频进行编码):0为编码,1为不编码
63 | //state: //用户自定义信息,如果提交了该字段,会在服务端上传完成回调时透传返回。
64 | }
65 | )
66 | polyvClient.startAll()
67 | }
68 |
--------------------------------------------------------------------------------
/src/assets/svg/用户.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/src/store/modules/user.js:
--------------------------------------------------------------------------------
1 | import { cloneDeep, isEmpty } from 'lodash'
2 | import { defineStore } from 'pinia'
3 | import { removeToken } from '@/utils/cookie'
4 |
5 | export const useUserStore = defineStore({
6 | id: 'user',
7 | state: () => ({
8 | mobile: '',
9 | realName: '',
10 | routerList: [],
11 | menuList: [],
12 | permissionList: [],
13 | breadcrumbMap: new Map()
14 | }),
15 | getters: {
16 | getMobile(state) {
17 | return state.mobile
18 | },
19 | getRealName(state) {
20 | return state.realName
21 | },
22 | getRouterList(state) {
23 | return state.routerList
24 | },
25 | getMenuList(state) {
26 | return state.menuList
27 | },
28 | getPermissionList(state) {
29 | return state.permissionList
30 | },
31 | getBreadcrumbMap(state) {
32 | return state.breadcrumbMap
33 | }
34 | },
35 | actions: {
36 | // 登录操作
37 | login(data) {
38 | this.mobile = data.mobile
39 | this.realName = data.realName
40 | this.routerList = data.routerList
41 | this.menuList = data.menuList
42 | this.permissionList = data.permissionList
43 | this.breadcrumbMap = buildBreadcrumbMap(data.menuList)
44 | },
45 |
46 | // logout
47 | logout() {
48 | this.routerList = []
49 | this.menuList = []
50 | this.breadcrumbMap = new Map()
51 | removeToken()
52 | }
53 | }
54 | })
55 |
56 | /**
57 | * 构建菜单父级集合,面包屑导航
58 | */
59 | function buildBreadcrumbMap(menuList) {
60 | let breadcrumbMaps = new Map()
61 | recursiveMap(menuList, [], breadcrumbMaps)
62 | return breadcrumbMaps
63 | }
64 | function recursiveMap(menuList, parentList, breadcrumbMaps) {
65 | for (const e of menuList) {
66 | if (e.parentId === 0) {
67 | parentList = []
68 | }
69 | let menuIdStr = e.id.toString()
70 | let cloneParentList = cloneDeep(parentList)
71 | cloneParentList.push({ id: menuIdStr, title: e.menuName })
72 | breadcrumbMaps.set(menuIdStr, cloneParentList)
73 | if (!isEmpty(e.children)) {
74 | // 递归
75 | recursiveMap(e.children, cloneParentList, breadcrumbMaps)
76 | }
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/src/components/Preview/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
8 |
9 |
10 |
11 |
12 |
79 |
80 |
--------------------------------------------------------------------------------
/src/layout/components/Navbar/User.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 领课网络
5 |
6 |
7 | 首页
8 |
9 |
10 |
11 | {{ realName }}
12 |
13 |
14 |
15 |
16 |
17 |
18 | 个人信息
19 | 退出登录
20 |
21 |
22 |
23 |
24 |
25 |
26 |
53 |
80 |
--------------------------------------------------------------------------------
/src/views/common/order/OrderForm.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
13 |
14 |
15 |
16 |
73 |
--------------------------------------------------------------------------------
/src/components/Selector/Lecturer/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | 查询
10 | 重置
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | {{ scope.row.lecturerName }}
19 |
20 |
21 |
22 |
23 | 选择
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
58 |
59 |
60 |
--------------------------------------------------------------------------------
/src/assets/svg/概况.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/views/dashboard/StatData.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | 数据统计
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
63 |
70 |
--------------------------------------------------------------------------------
/src/router/index.js:
--------------------------------------------------------------------------------
1 | import { createRouter, createWebHashHistory } from 'vue-router'
2 | import Layout from '@/layout/index.vue'
3 | import { useUserStore } from '@/store/modules/user'
4 | import { getToken } from '@/utils/cookie'
5 | import { PATH } from '@/utils/constants/system'
6 |
7 | // 静态路由
8 | const constantRoutes = [
9 | {
10 | path: '/',
11 | redirect: PATH.URL_DASHBOARD
12 | },
13 | {
14 | path: PATH.URL_LOGIN,
15 | component: () => import('@/views/login/index.vue')
16 | },
17 | {
18 | path: PATH.URL_404,
19 | component: () => import('@/views/404.vue'),
20 | meta: { title: '404' }
21 | },
22 | {
23 | path: PATH.URL_403,
24 | component: () => import('@/views/403.vue'),
25 | meta: { title: '403' }
26 | }
27 | ]
28 |
29 | const createRouters = (routerList) =>
30 | createRouter({
31 | history: createWebHashHistory(),
32 | routes: routerList,
33 | strict: true
34 | })
35 |
36 | const router = createRouters(constantRoutes)
37 |
38 | // 路由加载前
39 | router.beforeEach(async (to, from, next) => {
40 | const token = getToken()
41 | if (!token) {
42 | if (to.path === PATH.URL_LOGIN) {
43 | next()
44 | return
45 | }
46 | next({ path: PATH.URL_LOGIN })
47 | return
48 | }
49 | if (to.matched.length === 0) {
50 | next({ path: PATH.URL_404 })
51 | return
52 | }
53 | next()
54 | })
55 |
56 | export default router
57 |
58 | // 创建路由
59 | export function createNewRouter(data) {
60 | data = data ? data : useUserStore().routerList || []
61 | const menuList = data.filter((e) => e.path)
62 | const routerList = []
63 | const modules = import.meta.glob('../views/**/**.vue')
64 | for (const e of menuList) {
65 | const route = {
66 | path: e.path,
67 | name: e.id.toString(),
68 | meta: {
69 | // id
70 | id: e.id.toString(),
71 | // 组件名称
72 | componentName: e.id.toString(),
73 | // 组件标题
74 | title: e.menuName,
75 | // 组件图标
76 | icon: e.menuIcon
77 | },
78 | component: {}
79 | }
80 | route.component = modules[`../views${e.component}`]
81 | routerList.push(route)
82 | }
83 |
84 | router.addRoute({
85 | path: '/',
86 | meta: {},
87 | component: Layout,
88 | children: routerList
89 | })
90 | }
91 |
--------------------------------------------------------------------------------
/src/views/course/record/Course.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | 查询
11 | 重置
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 | 明细
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
59 |
--------------------------------------------------------------------------------
/src/components/Selector/Image/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
8 |
9 |
10 |
11 |
选择图片
12 |
{{ props.sugImg }}
13 |
14 |
15 |
16 |
17 |
18 |
61 |
62 |
86 |
--------------------------------------------------------------------------------
/src/views/system/log/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | 查询
11 | 重置
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | {{ scope.row.operation }}
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 | {{ scope.row.province }} {{ scope.row.city }}
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
58 |
--------------------------------------------------------------------------------
/src/views/course/chapter/ChapterForm.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
13 |
14 |
15 |
16 |
17 |
78 |
--------------------------------------------------------------------------------
/src/views/users/record/Account.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | 查询
8 | 重置
9 |
10 |
11 |
12 |
13 | 添加余额
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | -
26 | +
27 | {{ scope.row.consumeAmount }}
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
60 |
--------------------------------------------------------------------------------
/src/components/Editor/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
68 |
73 |
--------------------------------------------------------------------------------
/src/views/users/record/Course.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | 查询
11 | 重置
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 | 明细
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
60 |
--------------------------------------------------------------------------------
/src/views/course/resource/ResourceForm.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
16 |
17 |
18 |
19 |
20 |
79 |
--------------------------------------------------------------------------------
/src/api/users.js:
--------------------------------------------------------------------------------
1 | import { deleteRequest, getRequest, postRequest, putRequest } from '@/utils/request'
2 |
3 | export const usersApi = {
4 | // 用户账号金额消费
5 | usersAccountConsumeSave: (data) => {
6 | return postRequest('/user/admin/users/account/consume/save', data)
7 | },
8 | // 用户账号金额消费记录
9 | usersAccountConsumePage: (data) => {
10 | return postRequest('/user/admin/users/account/consume/page', data)
11 | },
12 |
13 | // 讲师分页
14 | lecturerPage: (params, pageCurrent = 1, pageSize = 20) => {
15 | return postRequest('/user/admin/lecturer/page', { pageCurrent, pageSize, ...params })
16 | },
17 | // 讲师查看
18 | lecturerView: (data) => {
19 | return getRequest('/user/admin/lecturer/view?id=' + data.id)
20 | },
21 | // 讲师修改
22 | lecturerEdit: (data) => {
23 | return putRequest('/user/admin/lecturer/edit', data)
24 | },
25 | // 讲师排序
26 | lecturerSort: (data) => {
27 | return putRequest('/user/admin/lecturer/sort', data)
28 | },
29 |
30 | // 讲师保存
31 | lecturerSave: (data) => {
32 | return postRequest('/user/admin/lecturer/save', data)
33 | },
34 |
35 | // 讲师删除
36 | lecturerDelete: (data) => {
37 | return deleteRequest('/user/admin/lecturer/delete?id=' + data.id)
38 | },
39 |
40 | // 用户分页
41 | usersPage: (params, pageCurrent = 1, pageSize = 20) => {
42 | return postRequest('/user/admin/users/page', { pageCurrent, pageSize, ...params })
43 | },
44 |
45 | // 用户修改
46 | usersEdit: (data) => {
47 | return putRequest('/user/admin/users/edit', data)
48 | },
49 |
50 | usersView(data) {
51 | return getRequest('/user/admin/users/view?id=' + data.id)
52 | },
53 | // 用户删除
54 | usersDelete: (data) => {
55 | return deleteRequest('/user/admin/users/delete?id=' + data.id)
56 | },
57 |
58 | // 登录日志
59 | logLoginPage: (params, pageCurrent = 1, pageSize = 20) => {
60 | return postRequest('/user/admin/users/log/page', { pageCurrent, pageSize, ...params })
61 | },
62 |
63 | // 用户课程分页
64 | userCoursePage: (params, pageCurrent = 1, pageSize = 20) => {
65 | return postRequest('/course/admin/user/course/page', { pageCurrent, pageSize, ...params })
66 | },
67 |
68 | // 订单
69 | orderInfoPage: (params, pageCurrent = 1, pageSize = 20) => {
70 | return postRequest('/user/admin/order/info/page', { pageCurrent, pageSize, ...params })
71 | },
72 | orderEdit: (data) => {
73 | return putRequest('/user/admin/order/info/edit', data)
74 | },
75 | orderInfoStat: (data) => {
76 | return getRequest('/user/admin/order/info/stat?userId=' + data.userId)
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/src/views/system/role/RoleForm.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
16 |
17 |
18 |
19 |
79 |
--------------------------------------------------------------------------------
/src/views/users/record/ConsumeForm.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
19 |
20 |
21 |
22 |
23 |
76 |
--------------------------------------------------------------------------------
/src/components/Cascader/Category/CategoryForm.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
13 |
14 |
15 |
16 |
17 |
83 |
--------------------------------------------------------------------------------
/src/views/course/category/CategoryForm.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
16 |
17 |
18 |
19 |
82 |
--------------------------------------------------------------------------------
/src/views/users/log/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | 查询
14 | 重置
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | {{ scope.row.province }} {{ scope.row.city }}
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
59 |
--------------------------------------------------------------------------------
/src/views/system/role/MenuSet.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
14 |
15 |
16 |
83 |
--------------------------------------------------------------------------------
/src/views/course/record/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
62 |
82 |
--------------------------------------------------------------------------------
/src/utils/base.js:
--------------------------------------------------------------------------------
1 | import { systemApi } from '@/api/system.js'
2 | import { getSessionStorage, setSessionStorage } from '@/utils/storage.js'
3 | import _ from 'lodash'
4 | import { JSEncrypt } from 'jsencrypt'
5 | import { useWebsiteStore } from '@/store/modules/website.js'
6 |
7 | /**
8 | * 格式化时长
9 | * @param time
10 | */
11 | export function formatTime(time) {
12 | let a = ~~(time / 3600)
13 | let b = ~~(time / 60) - a * 60
14 | let c = time % 60
15 | a = String(a).padStart(2, '0')
16 | b = String(b).padStart(2, '0')
17 | c = String(c).padStart(2, '0')
18 | if (a === '00') {
19 | return `${b}:${c}`
20 | } else {
21 | return `${a}:${b}:${c}`
22 | }
23 | }
24 |
25 | /**
26 | * 格式化时长
27 | * @param time
28 | */
29 | export function formatTimeTotal(time) {
30 | let a = ~~(time / 3600)
31 | let b = ~~(time / 60) - a * 60
32 | let c = time % 60
33 | a = String(a).padStart(2, '0')
34 | b = String(b).padStart(2, '0')
35 | c = String(c).padStart(2, '0')
36 | if (a === '00') {
37 | return `${b}分${c}秒`
38 | } else {
39 | return `${a}时${b}分${c}秒`
40 | }
41 | }
42 |
43 | // 文件大小转换
44 | export function transformSize(bytes) {
45 | // 文件大小转换
46 | const bt = parseInt(bytes)
47 | let result
48 | if (bt === 0) {
49 | result = '0B'
50 | } else {
51 | const k = 1024
52 | const sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
53 | const i = Math.floor(Math.log(bt) / Math.log(k))
54 | if (typeof i !== 'number') {
55 | result = '-'
56 | } else {
57 | result = (bt / Math.pow(k, i)).toFixed(2) + sizes[i]
58 | }
59 | }
60 | return result
61 | }
62 |
63 | export function cloneDeep(obj) {
64 | //return JSON.parse(JSON.stringify(obj))
65 | return _.cloneDeep(obj)
66 | }
67 |
68 | /**
69 | * 获取枚举
70 | */
71 | export async function getEnumList(enumName) {
72 | const enumAttr = getSessionStorage(enumName)
73 | if (enumAttr) {
74 | return enumAttr
75 | }
76 | const res = await systemApi.getEnum({ enumName })
77 | setSessionStorage(enumName, res)
78 | return getSessionStorage(enumName)
79 | }
80 |
81 | export async function getEnumObj(enumName) {
82 | let res = await getEnumList(enumName)
83 | return toObj(res)
84 | }
85 |
86 | function toObj(attr) {
87 | const obj = {}
88 | if (attr) {
89 | for (let i = 0; i < attr.length; i++) {
90 | obj[attr[i].code] = attr[i].desc
91 | }
92 | }
93 | return obj
94 | }
95 |
96 | export function encrypt(password, publicKey) {
97 | if (!publicKey) {
98 | publicKey = useWebsiteStore().getInfo.rsaLoginPublicKey
99 | }
100 | const crypt = new JSEncrypt()
101 | crypt.setPublicKey(publicKey)
102 | return crypt.encrypt(password)
103 | }
104 |
--------------------------------------------------------------------------------
/src/views/course/chapter/PeriodForm.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
16 |
17 |
18 |
19 |
20 |
85 |
--------------------------------------------------------------------------------
/src/views/users/list/UsersForm.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
22 |
23 |
24 |
25 |
26 |
83 |
--------------------------------------------------------------------------------
/src/views/course/resource/MoveModel.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
14 |
15 |
16 |
17 | {{ node.label }}
18 |
19 |
20 |
21 |
22 |
23 |
27 |
28 |
29 |
30 |
31 |
91 |
97 |
--------------------------------------------------------------------------------
/src/views/common/navigation/NavigationForm.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
19 |
20 |
21 |
22 |
85 |
--------------------------------------------------------------------------------
/src/views/common/zone/ZoneForm.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
19 |
20 |
21 |
22 |
23 |
86 |
--------------------------------------------------------------------------------
/src/views/common/link/LinkForm.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
19 |
20 |
21 |
22 |
87 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |

3 |
17 |
18 |
19 | ### 使用须知
20 |
21 | 1. 允许用于个人学习、毕业设计、教学案例、公益事业等。
22 | 2. 限制商用,若需要商业使用请咨询作者:18302045627(微信可加)。
23 | 3. 禁止将本项目的相关代码和相关资料进行任何形式任何名义的出售。
24 |
25 | ### 项目介绍
26 |
27 | 领课教育系统(roncoo-education)是基于领课网络多年的在线教育平台开发和运营经验打造出来的产品,致力于打造一个各行业都适用的分布式在线教育系统。系统采用前后端分离模式,前台采用vue.js为核心框架,后台采用Spring
28 | Cloud为核心框架。系统目前主要功能有课程点播功能,支持多家视频云的接入,课程附件管理功能,支持多家存储云的接入,可以帮助个人或者企业快速搭建一个轻量级的在线教育平台。
29 |
30 |
31 |
32 |  |
33 |  |
34 |
35 |
36 |  |
37 |  |
38 |
39 |
40 |  |
41 |  |
42 |
43 |
44 |  |
45 |  |
46 |
47 |
48 |
49 | ### 演示地址
50 |
51 | * 门户系统:[https://eduos.roncoos.com/](https://eduos.roncoos.com/)
52 | * 管理系统:[https://eduos.roncoos.com/admin/](https://eduos.roncoos.com/admin/)
53 | * 前端技术体系:Vue3 + Nuxt3 + Vite6 + Vue-Router + Element-Plus + Pinia + Axios
54 | * 后端技术体系:Spring Cloud Alibaba2023 + MySQL8 + Nacos + Seata + Mybatis + Druid
55 |
56 | ### 源码地址
57 |
58 | * 后端系统:roncoo-education(核心框架:Spring Cloud Alibaba):[码云](https://gitee.com/roncoocom/roncoo-education) | [Github](https://github.com/roncoo/roncoo-education) | [Gitcode](https://gitcode.com/roncoocom/roncoo-education)
59 | * 门户系统:roncoo-education-web(核心框架:Nuxt3):[码云](https://gitee.com/roncoocom/roncoo-education-web) | [Github](https://github.com/roncoo/roncoo-education-web) | [Gitcode](https://gitcode.com/roncoocom/roncoo-education-web)
60 | * 管理系统:roncoo-education-admin(核心框架:Vue3):[码云](https://gitee.com/roncoocom/roncoo-education-admin) | [Github](https://github.com/roncoo/roncoo-education-admin) | [Gitcode](https://gitcode.com/roncoocom/roncoo-education-admin)
61 |
62 | ---
63 | 关注微信公众号可获取更多学习资料(SQL脚本、部署教程、常见问题等)
64 |
65 |
--------------------------------------------------------------------------------
/src/assets/svg/系统.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/src/components/Upload/File/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | 上传
4 |
5 |
6 |
7 |
92 |
93 |
98 |
--------------------------------------------------------------------------------
/src/views/system/user/Password.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
16 |
17 |
18 |
19 |
20 |
94 |
--------------------------------------------------------------------------------
/src/components/Selector/Course/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | 查询
9 | 重置
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | {{ scope.row.courseName }}
18 |
19 | 免费
20 |
21 | ¥{{ scope.row.coursePrice }}¥{{ scope.row.rulingPrice }}
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | 选择
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
73 |
74 |
79 |
--------------------------------------------------------------------------------
/src/views/common/carousel/CarouselForm.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
19 |
20 |
21 |
22 |
88 |
--------------------------------------------------------------------------------
/src/views/system/user/RoleSet.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | 查询
11 | 重置
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 | 取消
25 | 确定
26 |
27 |
28 |
29 |
30 |
31 |
87 |
88 |
89 |
--------------------------------------------------------------------------------
/src/views/system/user/UserForm.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
22 |
23 |
24 |
25 |
90 |
--------------------------------------------------------------------------------
/src/views/course/category/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | 添加分类
8 | 刷新
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | {{ scope.row.categoryName }}
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 | 添加
28 |
29 | 编辑
30 |
31 |
32 |
33 | 更多操作
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 | 启用
42 | 禁用
43 |
44 |
45 | 删除
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
76 |
--------------------------------------------------------------------------------
/src/utils/table.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 表单封装
3 | */
4 | import { onMounted, reactive } from 'vue'
5 | import { ElMessage, ElMessageBox } from 'element-plus'
6 | import Sortable from 'sortablejs'
7 |
8 | export default function useTable(apis, paras = {}) {
9 | // 分页对象
10 | const page = reactive({
11 | pageCurrent: 1,
12 | pageSize: 20,
13 | totalCount: 0,
14 | list: [],
15 | loading: true
16 | })
17 |
18 | // 分页查询
19 | const handlePage = async () => {
20 | if (apis.page) {
21 | page.loading = true
22 | try {
23 | const res = await apis.page({
24 | pageCurrent: page.pageCurrent,
25 | pageSize: page.pageSize,
26 | ...paras,
27 | ...query
28 | })
29 | if (res) {
30 | page.list = res.list || res || []
31 | page.totalCount = res.totalCount || 0
32 |
33 | if (apis.sort) {
34 | await handleSort()
35 | }
36 | }
37 | } finally {
38 | page.loading = false
39 | }
40 | }
41 | }
42 |
43 | // 查询对象
44 | const query = reactive({})
45 |
46 | // 查询
47 | const handleQuery = () => {
48 | page.pageCurrent = 1
49 | // 分页查询
50 | handlePage()
51 | }
52 |
53 | // 重置
54 | const resetQuery = () => {
55 | for (let i in query) {
56 | query[i] = ''
57 | }
58 | handleQuery()
59 | }
60 |
61 | //删除功能
62 | const handleDelete = (data, tip = '') => {
63 | if (apis.delete) {
64 | ElMessageBox.confirm(tip || '确认删除当前数据?', '提示', {
65 | type: 'warning',
66 | cancelButtonText: '取消',
67 | confirmButtonText: '确认'
68 | }).then(async () => {
69 | page.loading = true
70 | try {
71 | const res = await apis.delete({ id: data.id })
72 | ElMessage.success({ message: res.msg ? res.msg : '操作成功' })
73 | await handlePage()
74 | } finally {
75 | page.loading = false
76 | }
77 | })
78 | }
79 | }
80 |
81 | // 状态修改
82 | const handleStatus = async (row) => {
83 | page.loading = true
84 | try {
85 | if (apis.status) {
86 | row.statusId = row.statusId ? 0 : 1
87 | const res = await apis.status({ id: row.id, statusId: row.statusId })
88 | ElMessage.success({ message: res.msg ? res.msg : '操作成功' })
89 | }
90 | } finally {
91 | page.loading = false
92 | }
93 | }
94 |
95 | // 排序
96 | const handleSort = async () => {
97 | const tbody = document.querySelector('.drag-table .el-table__body-wrapper tbody')
98 | Sortable.create(tbody, {
99 | onEnd({ oldIndex, newIndex }) {
100 | const row = page.list.splice(oldIndex, 1)[0]
101 | page.list.splice(newIndex, 0, row)
102 | const newSorts = page.list.map((item, index) => {
103 | return {
104 | id: item.id,
105 | sort: page.pageSize * (page.pageCurrent - 1) + index + 1
106 | }
107 | })
108 | apis.sort(newSorts).then(() => {
109 | ElMessage.success('排序完成')
110 | })
111 | }
112 | })
113 | }
114 |
115 | // 获取数据
116 | onMounted(handlePage)
117 |
118 | return {
119 | page,
120 | handlePage,
121 | query,
122 | handleQuery,
123 | resetQuery,
124 | handleDelete,
125 | handleStatus,
126 | handleSort
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/src/assets/svg/常用.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/src/views/course/record/Order.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | 查询
14 | 重置
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | {{ scope.row.orderNo }}
23 |
24 |
25 |
26 |
27 |
28 | ¥{{ scope.row.coursePrice }}
29 |
30 |
31 |
32 |
33 |
34 |
35 | {{ scope.row.payTime }}
36 | {{ scope.row.gmtCreate }}
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 | {{ scope.row.remarkCus }}
47 | {{ scope.row.remark }}
48 |
49 |
50 |
51 |
52 | 写备注
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
84 |
--------------------------------------------------------------------------------
/src/assets/images/logo.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/views/users/record/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | {{ usersInfo.nickname }}
8 |
9 |
10 |
11 | {{ usersInfo.mobile }}
12 | ¥{{ usersInfo.usersAccountViewResp?.availableAmount }}
13 | {{ usersInfo.userAge }}
14 |
15 |
16 |
17 |
18 | {{ usersInfo.country }}-{{ usersInfo.province }}-{{ usersInfo.city }}
19 | {{ usersInfo.remark }}
20 |
21 |
22 |
23 | {{ orderInfoStat.courseBuySum }}
24 | ¥{{ orderInfoStat.courseBuyMoney }}
25 | {{ userCourseStat.courseStudySum }}
26 | {{ formatTimeTotal(userCourseStat.courseStudyDuration) }}
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
77 |
--------------------------------------------------------------------------------
/src/views/system/app/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | 查询
11 | 重置
12 |
13 |
14 |
15 |
16 | 添加
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 | 编辑
35 |
36 |
37 | 更多操作
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 | 禁用
47 | 启用
48 |
49 |
50 |
51 | 删除
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
84 |
--------------------------------------------------------------------------------
/src/views/users/lecturer/LecturerForm.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
31 |
32 |
33 |
34 |
35 |
104 |
--------------------------------------------------------------------------------
/src/views/system/app/AppForm.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
29 |
30 |
31 |
32 |
104 |
--------------------------------------------------------------------------------
/src/views/users/lecturer/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | 查询
11 | 重置
12 |
13 |
14 |
15 |
16 | 添加讲师
17 |
18 |
19 |
20 |
21 |
22 |
23 | {{ scope.row.lecturerName }}
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 | 编辑
35 |
36 |
37 |
38 | 更多操作
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 | 启用
47 | 禁用
48 |
49 |
50 | 删除
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
85 |
--------------------------------------------------------------------------------
/src/views/common/link/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | 查询
11 | 重置
12 |
13 |
14 |
15 |
16 | 添加链接
17 |
18 |
19 |
20 |
21 |
22 |
23 | {{ scope.row.linkUrl }}
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 | 编辑
39 |
40 |
41 |
42 | 更多操作
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 | 启用
51 | 禁用
52 |
53 |
54 | 删除
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
88 |
--------------------------------------------------------------------------------
/src/views/common/navigation/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | 查询
11 | 重置
12 |
13 |
14 |
15 |
16 | 添加导航
17 |
18 |
19 |
20 |
21 |
22 |
23 | {{ scope.row.navUrl }}
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 | 编辑
39 |
40 |
41 |
42 | 更多操作
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 | 启用
51 | 禁用
52 |
53 |
54 | 删除
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
88 |
--------------------------------------------------------------------------------
/src/views/users/record/Order.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | 查询
11 | 重置
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | {{ scope.row.courseViewVO.courseName }}
22 |
23 | 免费
24 |
25 | ¥{{ scope.row.courseViewVO.coursePrice }}¥{{ scope.row.courseViewVO.rulingPrice }}
26 |
27 |
28 |
29 |
30 |
31 |
32 | {{ scope.row.orderNo }}
33 |
34 |
35 |
36 |
37 | ¥{{ scope.row.coursePrice }}
38 |
39 |
40 |
41 |
42 |
43 |
44 | {{ scope.row.payTime }}
45 | {{ scope.row.gmtCreate }}
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 | {{ scope.row.remarkCus }}
56 | {{ scope.row.remark }}
57 |
58 |
59 |
60 |
61 | 写备注
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
93 |
--------------------------------------------------------------------------------
/src/views/system/role/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | 查询
11 | 重置
12 |
13 |
14 |
15 |
16 | 添加角色
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | 编辑
30 |
31 | 分配菜单
32 |
33 |
34 | 更多操作
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 | 禁用
44 | 启用
45 |
46 |
47 |
48 | 删除
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
95 |
--------------------------------------------------------------------------------