Compare commits

..

3 Commits

  1. 2
      .env.development
  2. 4
      .env_1.development
  3. 3
      .env_1.production
  4. 4
      .env_1.test
  5. 120
      .eslintrc.cjs
  6. 65
      .eslintrc_1.cjs
  7. 9
      .prettierrc_1.json
  8. 53
      .stylelintrc_1.cjs
  9. 18
      README_1.md
  10. 2
      _1.eslintignore
  11. 24
      _1.gitignore
  12. 4
      _1.stylelintignore
  13. 15
      index_1.html
  14. 28
      mock/user.ts
  15. 69
      mock/user_1.ts
  16. 6216
      pnpm-lock.yaml
  17. BIN
      public/0.jpg
  18. BIN
      public/1.jpg
  19. BIN
      public/2.jpg
  20. BIN
      public/wl.png
  21. 10
      src/api/user/crouse.js
  22. 1
      src/assets/icons/dianzan.svg
  23. 1
      src/assets/icons/dianzanred.svg
  24. 1
      src/assets/icons/点赞.svg
  25. BIN
      src/assets/images/0.jpg
  26. BIN
      src/assets/images/1.jpg
  27. BIN
      src/assets/images/1.png
  28. BIN
      src/assets/images/3.png
  29. BIN
      src/assets/images/ck.png
  30. BIN
      src/assets/images/dx.png
  31. BIN
      src/assets/images/kc.jpg
  32. BIN
      src/assets/images/logo.png
  33. BIN
      src/assets/images/logo1.png
  34. BIN
      src/assets/images/ls.jpg
  35. BIN
      src/assets/images/rjgz.jpg
  36. BIN
      src/assets/images/rwd.png
  37. BIN
      src/assets/images/sj.png
  38. BIN
      src/assets/images/wl.png
  39. BIN
      src/assets/images/xs.jpg
  40. BIN
      src/assets/images/zy.jpg
  41. BIN
      src/assets/images/图灵云logo.png
  42. BIN
      src/assets/images/小旗子.png
  43. BIN
      src/assets/images/搜索.png
  44. BIN
      src/assets/images/点赞 (1).png
  45. BIN
      src/assets/images/点赞.png
  46. BIN
      src/assets/images/知识点.png
  47. BIN
      src/assets/images/统计计算.png
  48. BIN
      src/assets/images/课程.png
  49. 3
      src/layout/index.vue
  50. 4
      src/layout/main/index.vue
  51. 2
      src/layout/menu/index.vue
  52. 112
      src/permission.ts
  53. 4
      src/router/index.ts
  54. 13
      src/views/MyCourseStudy/Courselikes.vue
  55. 13
      src/views/MyCourseStudy/courseCollections.vue
  56. 13
      src/views/MyCourseStudy/learningProcess.vue
  57. 13
      src/views/course/CourseObjectives.vue
  58. 289
      src/views/course/basicCourseInformation.vue
  59. 61
      src/views/course/components/KnowledgeEdit.vue
  60. 36
      src/views/course/components/PageContainer.vue
  61. 184
      src/views/course/components/courseEdit.vue
  62. 13
      src/views/course/curriculumMap.vue
  63. 117
      src/views/course/knowledgePoints.vue
  64. 29
      src/views/home/index.vue
  65. 1
      src/views/login/index.vue
  66. 60
      src/views/portal/LearningPathRecommendations.vue
  67. 538
      src/views/portal/courseHomepage.vue
  68. 351
      src/views/portal/courseReports.vue
  69. 1044
      src/views/portal/index.vue
  70. 13
      src/views/portal/knowledgePointLearning.vue

@ -1,4 +1,4 @@
# 变量必须以 VITE_ 为前缀才能暴露给外部读取
NODE_ENV = 'development'
VITE_APP_TITLE = '无糖运营平台'
VITE_APP_BASE_API = '/api'
VITE_APP_BASE_API = 'http://127.0.0.1:8080'

@ -0,0 +1,4 @@
# 变量必须以 VITE_ 为前缀才能暴露给外部读取
NODE_ENV = 'development'
VITE_APP_TITLE = '无糖运营平台'
VITE_APP_BASE_API = '/api'

@ -0,0 +1,3 @@
NODE_ENV = 'production'
VITE_APP_TITLE = '无糖运营平台'
VITE_APP_BASE_API = '/prod-api'

@ -0,0 +1,4 @@
# 变量必须以 VITE_ 为前缀才能暴露给外部读取
NODE_ENV = 'test'
VITE_APP_TITLE = '无糖运营平台'
VITE_APP_BASE_API = '/test-api'

@ -1,63 +1,65 @@
// @see https://eslint.bootcss.com/docs/rules/
module.exports = {
env: {
browser: true,
es2021: true,
node: true,
jest: true,
env: {
browser: true,
es2021: true,
node: true,
jest: true,
},
globals: {
VANTA: 'readonly', //VANTA 已经cdn引入 这里拒绝eslint报错 全局声明一下
ElMessage: 'readonly',
ElMessageBox: 'readonly',
ElLoading: 'readonly',
},
/* 指定如何解析语法 */
parser: 'vue-eslint-parser',
/** 优先级低于 parse 的语法解析配置 */
parserOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
parser: '@typescript-eslint/parser',
jsxPragma: 'React',
ecmaFeatures: {
jsx: true,
},
"globals": {
"VANTA": "readonly" //VANTA 已经cdn引入 这里拒绝eslint报错 全局声明一下
},
/* 指定如何解析语法 */
parser: 'vue-eslint-parser',
/** 优先级低于 parse 的语法解析配置 */
parserOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
parser: '@typescript-eslint/parser',
jsxPragma: 'React',
ecmaFeatures: {
jsx: true,
},
},
/* 继承已有的规则 */
extends: [
'eslint:recommended',
'plugin:vue/vue3-essential',
'plugin:@typescript-eslint/recommended',
'plugin:prettier/recommended',
],
plugins: ['vue', '@typescript-eslint'],
/*
* "off" 或 0 ==> 关闭规则
* "warn" 或 1 ==> 打开的规则作为警告(不影响代码执行)
* "error" 或 2 ==> 规则作为一个错误(代码不能执行,界面报错)
*/
rules: {
// eslint(https://eslint.bootcss.com/docs/rules/)
'no-var': 'error', // 要求使用 let 或 const 而不是 var
'no-multiple-empty-lines': ['warn', { max: 1 }], // 不允许多个空行
'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
'no-unexpected-multiline': 'error', // 禁止空余的多行
'no-useless-escape': 'off', // 禁止不必要的转义字符
// typeScript (https://typescript-eslint.io/rules)
'@typescript-eslint/no-unused-vars': 'error', // 禁止定义未使用的变量
'@typescript-eslint/prefer-ts-expect-error': 'off', // 禁止使用 @ts-ignore
"@typescript-eslint/ban-ts-ignore": "off",
'@typescript-eslint/no-explicit-any': 'off', // 禁止使用 any 类型
'@typescript-eslint/no-non-null-assertion': 'off',
'@typescript-eslint/no-namespace': 'off', // 禁止使用自定义 TypeScript 模块和命名空间。
'@typescript-eslint/semi': 'off',
// eslint-plugin-vue (https://eslint.vuejs.org/rules/)
'vue/multi-word-component-names': 'off', // 要求组件名称始终为 “-” 链接的单词
'vue/script-setup-uses-vars': 'error', // 防止<script setup>使用的变量<template>被标记为未使用
'vue/no-mutating-props': 'off', // 不允许组件 prop的改变
'vue/attribute-hyphenation': 'off', // 对模板中的自定义组件强制执行属性命名样式
},
}
},
/* 继承已有的规则 */
extends: [
'eslint:recommended',
'plugin:vue/vue3-essential',
'plugin:@typescript-eslint/recommended',
'plugin:prettier/recommended',
],
plugins: ['vue', '@typescript-eslint'],
/*
* "off" 或 0 ==> 关闭规则
* "warn" 或 1 ==> 打开的规则作为警告(不影响代码执行)
* "error" 或 2 ==> 规则作为一个错误(代码不能执行,界面报错)
*/
rules: {
// eslint(https://eslint.bootcss.com/docs/rules/)
'no-var': 'error', // 要求使用 let 或 const 而不是 var
'no-multiple-empty-lines': ['warn', { max: 1 }], // 不允许多个空行
'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
'no-unexpected-multiline': 'error', // 禁止空余的多行
'no-useless-escape': 'off', // 禁止不必要的转义字符
// typeScript (https://typescript-eslint.io/rules)
'@typescript-eslint/no-unused-vars': 'error', // 禁止定义未使用的变量
'@typescript-eslint/prefer-ts-expect-error': 'off', // 禁止使用 @ts-ignore
'@typescript-eslint/ban-ts-ignore': 'off',
'@typescript-eslint/no-explicit-any': 'off', // 禁止使用 any 类型
'@typescript-eslint/no-non-null-assertion': 'off',
'@typescript-eslint/no-namespace': 'off', // 禁止使用自定义 TypeScript 模块和命名空间。
'@typescript-eslint/semi': 'off',
// eslint-plugin-vue (https://eslint.vuejs.org/rules/)
'vue/multi-word-component-names': 'off', // 要求组件名称始终为 “-” 链接的单词
'vue/script-setup-uses-vars': 'error', // 防止<script setup>使用的变量<template>被标记为未使用
'vue/no-mutating-props': 'off', // 不允许组件 prop的改变
'vue/attribute-hyphenation': 'off', // 对模板中的自定义组件强制执行属性命名样式
},
}

@ -0,0 +1,65 @@
// @see https://eslint.bootcss.com/docs/rules/
module.exports = {
env: {
browser: true,
es2021: true,
node: true,
jest: true,
},
globals: {
VANTA: 'readonly', //VANTA 已经cdn引入 这里拒绝eslint报错 全局声明一下
ElMessage: 'readonly',
ElMessageBox: 'readonly',
ElLoading: 'readonly',
},
/* 指定如何解析语法 */
parser: 'vue-eslint-parser',
/** 优先级低于 parse 的语法解析配置 */
parserOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
parser: '@typescript-eslint/parser',
jsxPragma: 'React',
ecmaFeatures: {
jsx: true,
},
},
/* 继承已有的规则 */
extends: [
'eslint:recommended',
'plugin:vue/vue3-essential',
'plugin:@typescript-eslint/recommended',
'plugin:prettier/recommended',
],
plugins: ['vue', '@typescript-eslint'],
/*
* "off" 或 0 ==> 关闭规则
* "warn" 或 1 ==> 打开的规则作为警告(不影响代码执行)
* "error" 或 2 ==> 规则作为一个错误(代码不能执行,界面报错)
*/
rules: {
// eslint(https://eslint.bootcss.com/docs/rules/)
'no-var': 'error', // 要求使用 let 或 const 而不是 var
'no-multiple-empty-lines': ['warn', { max: 1 }], // 不允许多个空行
'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
'no-unexpected-multiline': 'error', // 禁止空余的多行
'no-useless-escape': 'off', // 禁止不必要的转义字符
// typeScript (https://typescript-eslint.io/rules)
'@typescript-eslint/no-unused-vars': 'error', // 禁止定义未使用的变量
'@typescript-eslint/prefer-ts-expect-error': 'off', // 禁止使用 @ts-ignore
'@typescript-eslint/ban-ts-ignore': 'off',
'@typescript-eslint/no-explicit-any': 'off', // 禁止使用 any 类型
'@typescript-eslint/no-non-null-assertion': 'off',
'@typescript-eslint/no-namespace': 'off', // 禁止使用自定义 TypeScript 模块和命名空间。
'@typescript-eslint/semi': 'off',
// eslint-plugin-vue (https://eslint.vuejs.org/rules/)
'vue/multi-word-component-names': 'off', // 要求组件名称始终为 “-” 链接的单词
'vue/script-setup-uses-vars': 'error', // 防止<script setup>使用的变量<template>被标记为未使用
'vue/no-mutating-props': 'off', // 不允许组件 prop的改变
'vue/attribute-hyphenation': 'off', // 对模板中的自定义组件强制执行属性命名样式
},
}

@ -0,0 +1,9 @@
{
"singleQuote": true,
"semi": false,
"bracketSpacing": true,
"htmlWhitespaceSensitivity": "ignore",
"endOfLine": "auto",
"trailingComma": "all",
"tabWidth": 2
}

@ -0,0 +1,53 @@
// @see https://stylelint.bootcss.com/
module.exports = {
extends: [
'stylelint-config-standard', // 配置stylelint拓展插件
'stylelint-config-standard-vue', // 配置 vue 中 template 样式格式化
'stylelint-config-standard-scss', // 配置stylelint scss插件
'stylelint-config-recommended-vue/scss', // 配置 vue 中 scss 样式格式化
'stylelint-config-recess-order', // 配置stylelint css属性书写顺序插件,
'stylelint-config-prettier', // 配置stylelint和prettier兼容
],
overrides: [
{
files: ['**/*.(scss|css|vue|html)'],
customSyntax: 'postcss-scss',
},
{
files: ['**/*.(html|vue)'],
customSyntax: 'postcss-html',
},
],
ignoreFiles: [
'**/*.js',
'**/*.jsx',
'**/*.tsx',
'**/*.ts',
'**/*.json',
'**/*.md',
'**/*.yaml',
],
/**
* null => 关闭该规则
* always => 必须
*/
rules: {
'value-keyword-case': null, // 在 css 中使用 v-bind,不报错
'no-descending-specificity': null, // 禁止在具有较高优先级的选择器后出现被其覆盖的较低优先级的选择器
'function-url-quotes': 'always', // 要求或禁止 URL 的引号 "always(必须加上引号)"|"never(没有引号)"
'no-empty-source': null, // 关闭禁止空源码
'selector-class-pattern': null, // 关闭强制选择器类名的格式
'property-no-unknown': null, // 禁止未知的属性(true 为不允许)
'block-opening-brace-space-before': 'always', //大括号之前必须有一个空格或不能有空白符
'value-no-vendor-prefix': null, // 关闭 属性值前缀 --webkit-box
'property-no-vendor-prefix': null, // 关闭 属性前缀 -webkit-mask
'selector-pseudo-class-no-unknown': [
// 不允许未知的选择器
true,
{
ignorePseudoClasses: ['global', 'v-deep', 'deep'], // 忽略属性,修改element默认样式的时候能使用到
},
],
},
}

@ -0,0 +1,18 @@
# Vue 3 + TypeScript + Vite
This template should help get you started developing with Vue 3 and TypeScript in Vite. The template uses Vue 3 `<script setup>` SFCs, check out the [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to learn more.
## Recommended IDE Setup
- [VS Code](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur) + [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin).
## Type Support For `.vue` Imports in TS
TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin) to make the TypeScript language service aware of `.vue` types.
If the standalone TypeScript plugin doesn't feel fast enough to you, Volar has also implemented a [Take Over Mode](https://github.com/johnsoncodehk/volar/discussions/471#discussioncomment-1361669) that is more performant. You can enable it by the following steps:
1. Disable the built-in TypeScript Extension
1. Run `Extensions: Show Built-in Extensions` from VSCode's command palette
2. Find `TypeScript and JavaScript Language Features`, right click and select `Disable (Workspace)`
2. Reload the VSCode window by running `Developer: Reload Window` from the command palette.

@ -0,0 +1,2 @@
dist
node_modules

24
_1.gitignore vendored

@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

@ -0,0 +1,4 @@
/node_modules/*
/dist/*
/html/*
/public/*

@ -0,0 +1,15 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>教学一体化后师生后台</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r134/three.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vanta@latest/dist/vanta.globe.min.js"></script>
</body>
</html>

@ -10,18 +10,7 @@ function createUserList() {
desc: '平台管理员',
roles: ['平台管理员'],
buttons: ['cuser.detail'],
routes: [
'Home',
'Course',
'Student',
'Group',
'Message',
'BasicCourseInformation',
'CourseObjectives',
'CourseChapters',
'KnowledgePoints',
'CurriculumMap',
], //老师权限
routes: ['Home', 'Course', 'Student', 'Group', 'Message','BasicCourseInformation','CourseObjectives','CourseChapters','KnowledgePoints','CurriculumMap'], //老师权限
token: 'Admin Token',
},
{
@ -33,20 +22,7 @@ function createUserList() {
desc: '系统管理员',
roles: ['系统管理员'],
buttons: ['cuser.detail', 'cuser.user'],
routes: [
'Home',
'MyCourseStudy',
'CourseResources',
'Message',
'LearningProcess',
'CourseCollections',
'Courselikes',
'WebHome',
'CourseHome',
'LearningPathRecommendations',
'KnowledgePointLearning',
'CourseReports',
], //学生权限
routes: ['Home', 'MyCourseStudy', 'CourseResources', 'Message','LearningProcess','CourseCollections','Courselikes','WebHome','CourseHome','LearningPathRecommendations','KnowledgePointLearning','CourseReports'], //学生权限
token: 'System Token',
},
]

@ -0,0 +1,69 @@
//用户信息数据
function createUserList() {
return [
{
userId: 1,
avatar:
'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif',
username: 'admin',
password: '111111',
desc: '平台管理员',
roles: ['平台管理员'],
buttons: ['cuser.detail'],
routes: ['Home', 'Course', 'Student', 'Group', 'Message','BasicCourseInformation','CourseObjectives','CourseChapters','KnowledgePoints','CurriculumMap'], //老师权限
token: 'Admin Token',
},
{
userId: 2,
avatar:
'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif',
username: 'student',
password: '111111',
desc: '系统管理员',
roles: ['系统管理员'],
buttons: ['cuser.detail', 'cuser.user'],
routes: ['Home', 'MyCourseStudy', 'CourseResources', 'Message','LearningProcess','CourseCollections','Courselikes','WebHome','CourseHome','LearningPathRecommendations','KnowledgePointLearning','CourseReports'], //学生权限
token: 'System Token',
},
]
}
export default [
// 用户登录接口
{
url: '/api/user/login', //请求地址
method: 'post', //请求方式
response: ({ body }) => {
//获取请求体携带过来的用户名与密码
const { username, password } = body
//调用获取用户信息函数,用于判断是否有此用户
const checkUser = createUserList().find(
(item) => item.username === username && item.password === password,
)
//没有用户返回失败信息
if (!checkUser) {
return { code: 201, data: { message: '账号或者密码不正确' } }
}
//如果有返回成功信息
const { token } = checkUser
return { code: 200, data: { token } }
},
},
// 获取用户信息
{
url: '/api/user/info',
method: 'get',
response: (request) => {
//获取请求头携带token
const token = request.headers.token
//查看用户信息是否包含有次token用户
const checkUser = createUserList().find((item) => item.token === token)
//没有返回失败的信息
if (!checkUser) {
return { code: 201, data: { message: '获取用户信息失败' } }
}
//如果有返回成功信息
return { code: 200, data: { checkUser } }
},
},
]

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 548 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 183 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

@ -0,0 +1,10 @@
import request from '@/utils/request'
export const getCourseListApi = () => {
return request.get('/coursesteacher/page?teacherId=2140110334')
}
export const editCourseApi = () => {
return request.put('/coursesTeacher')
}
export const addCourseApi = (data) => {
return request.post('/courseTeacher/addCourse', data)
}

@ -1 +0,0 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1716801285381" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3407" data-spm-anchor-id="a313x.search_index.0.i4.36a13a81tckiXp" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M190.193225 471.411583c14.446014 0 26.139334-11.718903 26.139334-26.13831 0-14.44499-11.69332-26.164916-26.139334-26.164916-0.271176 0-0.490164 0.149403-0.73678 0.149403l-62.496379 0.146333c-1.425466-0.195451-2.90005-0.295735-4.373611-0.295735-19.677155 0-35.621289 16.141632-35.621289 36.114522L86.622358 888.550075c0 19.949354 15.96767 35.597753 35.670407 35.597753 1.916653 0 3.808746 0.292666 5.649674 0l61.022819 0.022513c0.099261 0 0.148379 0.048095 0.24764 0.048095 0.097214 0 0.146333-0.048095 0.24457-0.048095l0.73678 0 0-0.148379c13.413498-0.540306 24.174586-11.422144 24.174586-24.960485 0-13.55983-10.760065-24.441669-24.174586-24.981974l0-0.393973-50.949392 0 1.450025-402.275993L190.193225 471.409536z" fill="#5D5D5D" p-id="3408"></path><path d="M926.52241 433.948343c-19.283182-31.445176-47.339168-44.172035-81.289398-45.546336-1.77032-0.246617-3.536546-0.39295-5.380544-0.39295l-205.447139-0.688685c13.462616-39.059598 22.698978-85.58933 22.698978-129.317251 0-28.349675-3.193739-55.962569-9.041934-82.542948l-0.490164 0.049119c-10.638291-46.578852-51.736315-81.31498-100.966553-81.31498-57.264215 0-95.466282 48.15065-95.466282 106.126063 0 3.241834-0.294712 6.387477 0 9.532097-2.996241 108.386546-91.240027 195.548698-196.23636 207.513194l0 54.881958-0.785899 222.227314 0 229.744521 10.709923 0 500.025271 0.222057 8.746198-0.243547c19.35686 0.049119 30.239721-4.817726 47.803749-16.116049 16.682961-10.761088 29.236881-25.50079 37.490869-42.156122 2.260483-3.341095 4.028757-7.075139 5.106298-11.20111l77.018118-344.324116c1.056052-4.053316 1.348718-8.181333 1.056052-12.160971C943.643346 476.446249 938.781618 453.944769 926.52241 433.948343zM893.82573 486.837924l-82.983993 367.783411-0.099261-0.049119c-2.555196 6.141884-6.879688 11.596106-12.872169 15.427364-4.177136 2.727111-8.773827 4.351098-13.414521 4.964058-1.49812-0.195451-3.046383 0-4.620227 0l-477.028511-0.540306-0.171915-407.408897c89.323375-40.266076 154.841577-79.670527 188.596356-173.661202 0.072655 0.024559 0.124843 0.049119 0.195451 0.072655 2.99931-9.137101 6.313799-20.73423 8.697079-33.164331 5.551436-29.185716 5.258771-58.123792 5.258771-58.123792-4.937452-37.98001 25.940812-52.965306 44.364417-52.965306 25.304316 0.860601 50.263777 33.656541 50.263777 52.326762 0 0 5.600555 27.563776 5.649674 57.190537 0.048095 37.366026-4.6673 56.847729-4.6673 56.847729l-0.466628 0c-5.872754 30.879288-16.214287 60.138682-30.464849 86.964654l0.36839 0.342808c-2.358721 4.815679-3.709485 10.220782-3.709485 15.943111 0 19.922748 19.088754 21.742187 38.765909 21.742187l238.761895 0.270153c0 0 14.666024 0.465604 14.690584 0.465604l0 0.100284c12.132318-0.638543 24.221658 5.207605 31.100322 16.409738 5.504364 9.016351 6.437619 19.6045 3.486404 28.988218L893.82573 486.837924z" fill="#5D5D5D" p-id="3409"></path><path d="M264.827039 924.31872c0.319272 0.024559 0.441045 0.024559 0.295735-0.024559 0.243547-0.048095 0.367367-0.074701-0.295735-0.074701s-0.539282 0.026606-0.271176 0.074701C264.43409 924.343279 264.532327 924.343279 264.827039 924.31872z" fill="#5D5D5D" p-id="3410"></path></svg>

Before

Width:  |  Height:  |  Size: 3.4 KiB

@ -1 +0,0 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1716801285381" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3407" data-spm-anchor-id="a313x.search_index.0.i4.36a13a81tckiXp" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M190.193225 471.411583c14.446014 0 26.139334-11.718903 26.139334-26.13831 0-14.44499-11.69332-26.164916-26.139334-26.164916-0.271176 0-0.490164 0.149403-0.73678 0.149403l-62.496379 0.146333c-1.425466-0.195451-2.90005-0.295735-4.373611-0.295735-19.677155 0-35.621289 16.141632-35.621289 36.114522L86.622358 888.550075c0 19.949354 15.96767 35.597753 35.670407 35.597753 1.916653 0 3.808746 0.292666 5.649674 0l61.022819 0.022513c0.099261 0 0.148379 0.048095 0.24764 0.048095 0.097214 0 0.146333-0.048095 0.24457-0.048095l0.73678 0 0-0.148379c13.413498-0.540306 24.174586-11.422144 24.174586-24.960485 0-13.55983-10.760065-24.441669-24.174586-24.981974l0-0.393973-50.949392 0 1.450025-402.275993L190.193225 471.409536z" fill="#d81e06" p-id="3408"></path><path d="M926.52241 433.948343c-19.283182-31.445176-47.339168-44.172035-81.289398-45.546336-1.77032-0.246617-3.536546-0.39295-5.380544-0.39295l-205.447139-0.688685c13.462616-39.059598 22.698978-85.58933 22.698978-129.317251 0-28.349675-3.193739-55.962569-9.041934-82.542948l-0.490164 0.049119c-10.638291-46.578852-51.736315-81.31498-100.966553-81.31498-57.264215 0-95.466282 48.15065-95.466282 106.126063 0 3.241834-0.294712 6.387477 0 9.532097-2.996241 108.386546-91.240027 195.548698-196.23636 207.513194l0 54.881958-0.785899 222.227314 0 229.744521 10.709923 0 500.025271 0.222057 8.746198-0.243547c19.35686 0.049119 30.239721-4.817726 47.803749-16.116049 16.682961-10.761088 29.236881-25.50079 37.490869-42.156122 2.260483-3.341095 4.028757-7.075139 5.106298-11.20111l77.018118-344.324116c1.056052-4.053316 1.348718-8.181333 1.056052-12.160971C943.643346 476.446249 938.781618 453.944769 926.52241 433.948343zM893.82573 486.837924l-82.983993 367.783411-0.099261-0.049119c-2.555196 6.141884-6.879688 11.596106-12.872169 15.427364-4.177136 2.727111-8.773827 4.351098-13.414521 4.964058-1.49812-0.195451-3.046383 0-4.620227 0l-477.028511-0.540306-0.171915-407.408897c89.323375-40.266076 154.841577-79.670527 188.596356-173.661202 0.072655 0.024559 0.124843 0.049119 0.195451 0.072655 2.99931-9.137101 6.313799-20.73423 8.697079-33.164331 5.551436-29.185716 5.258771-58.123792 5.258771-58.123792-4.937452-37.98001 25.940812-52.965306 44.364417-52.965306 25.304316 0.860601 50.263777 33.656541 50.263777 52.326762 0 0 5.600555 27.563776 5.649674 57.190537 0.048095 37.366026-4.6673 56.847729-4.6673 56.847729l-0.466628 0c-5.872754 30.879288-16.214287 60.138682-30.464849 86.964654l0.36839 0.342808c-2.358721 4.815679-3.709485 10.220782-3.709485 15.943111 0 19.922748 19.088754 21.742187 38.765909 21.742187l238.761895 0.270153c0 0 14.666024 0.465604 14.690584 0.465604l0 0.100284c12.132318-0.638543 24.221658 5.207605 31.100322 16.409738 5.504364 9.016351 6.437619 19.6045 3.486404 28.988218L893.82573 486.837924z" fill="#d81e06" p-id="3409"></path><path d="M264.827039 924.31872c0.319272 0.024559 0.441045 0.024559 0.295735-0.024559 0.243547-0.048095 0.367367-0.074701-0.295735-0.074701s-0.539282 0.026606-0.271176 0.074701C264.43409 924.343279 264.532327 924.343279 264.827039 924.31872z" fill="#d81e06" p-id="3410"></path></svg>

Before

Width:  |  Height:  |  Size: 3.4 KiB

@ -1 +0,0 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1716799682617" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3051" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M190.193225 471.411583c14.446014 0 26.139334-11.718903 26.139334-26.13831 0-14.44499-11.69332-26.164916-26.139334-26.164916-0.271176 0-0.490164 0.149403-0.73678 0.149403l-62.496379 0.146333c-1.425466-0.195451-2.90005-0.295735-4.373611-0.295735-19.677155 0-35.621289 16.141632-35.621289 36.114522L86.622358 888.550075c0 19.949354 15.96767 35.597753 35.670407 35.597753 1.916653 0 3.808746 0.292666 5.649674 0l61.022819 0.022513c0.099261 0 0.148379 0.048095 0.24764 0.048095 0.097214 0 0.146333-0.048095 0.24457-0.048095l0.73678 0 0-0.148379c13.413498-0.540306 24.174586-11.422144 24.174586-24.960485 0-13.55983-10.760065-24.441669-24.174586-24.981974l0-0.393973-50.949392 0 1.450025-402.275993L190.193225 471.409536z" fill="#d81e06" p-id="3052"></path><path d="M926.52241 433.948343c-19.283182-31.445176-47.339168-44.172035-81.289398-45.546336-1.77032-0.246617-3.536546-0.39295-5.380544-0.39295l-205.447139-0.688685c13.462616-39.059598 22.698978-85.58933 22.698978-129.317251 0-28.349675-3.193739-55.962569-9.041934-82.542948l-0.490164 0.049119c-10.638291-46.578852-51.736315-81.31498-100.966553-81.31498-57.264215 0-95.466282 48.15065-95.466282 106.126063 0 3.241834-0.294712 6.387477 0 9.532097-2.996241 108.386546-91.240027 195.548698-196.23636 207.513194l0 54.881958-0.785899 222.227314 0 229.744521 10.709923 0 500.025271 0.222057 8.746198-0.243547c19.35686 0.049119 30.239721-4.817726 47.803749-16.116049 16.682961-10.761088 29.236881-25.50079 37.490869-42.156122 2.260483-3.341095 4.028757-7.075139 5.106298-11.20111l77.018118-344.324116c1.056052-4.053316 1.348718-8.181333 1.056052-12.160971C943.643346 476.446249 938.781618 453.944769 926.52241 433.948343zM893.82573 486.837924l-82.983993 367.783411-0.099261-0.049119c-2.555196 6.141884-6.879688 11.596106-12.872169 15.427364-4.177136 2.727111-8.773827 4.351098-13.414521 4.964058-1.49812-0.195451-3.046383 0-4.620227 0l-477.028511-0.540306-0.171915-407.408897c89.323375-40.266076 154.841577-79.670527 188.596356-173.661202 0.072655 0.024559 0.124843 0.049119 0.195451 0.072655 2.99931-9.137101 6.313799-20.73423 8.697079-33.164331 5.551436-29.185716 5.258771-58.123792 5.258771-58.123792-4.937452-37.98001 25.940812-52.965306 44.364417-52.965306 25.304316 0.860601 50.263777 33.656541 50.263777 52.326762 0 0 5.600555 27.563776 5.649674 57.190537 0.048095 37.366026-4.6673 56.847729-4.6673 56.847729l-0.466628 0c-5.872754 30.879288-16.214287 60.138682-30.464849 86.964654l0.36839 0.342808c-2.358721 4.815679-3.709485 10.220782-3.709485 15.943111 0 19.922748 19.088754 21.742187 38.765909 21.742187l238.761895 0.270153c0 0 14.666024 0.465604 14.690584 0.465604l0 0.100284c12.132318-0.638543 24.221658 5.207605 31.100322 16.409738 5.504364 9.016351 6.437619 19.6045 3.486404 28.988218L893.82573 486.837924z" fill="#d81e06" p-id="3053"></path><path d="M264.827039 924.31872c0.319272 0.024559 0.441045 0.024559 0.295735-0.024559 0.243547-0.048095 0.367367-0.074701-0.295735-0.074701s-0.539282 0.026606-0.271176 0.074701C264.43409 924.343279 264.532327 924.343279 264.827039 924.31872z" fill="#d81e06" p-id="3054"></path></svg>

Before

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 548 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 183 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 466 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 437 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

@ -17,7 +17,7 @@
text-color="#fff"
:collapse="LayoutSettingStoe.fold"
>
<Menu :menuList="usePermissionStore.asyncRouter" />
<Menu :menuList="constantRoute" />
</el-menu>
</el-scrollbar>
</div>
@ -49,6 +49,7 @@ import { useRoute } from 'vue-router'
import Tabbar from './tabbar/index.vue'
import LoGo from './logo/index.vue'
import Menu from './menu/index.vue'
import {constantRoute} from '@/router/routers'
//
// import userUserStore from '@/store/modules/user'
// import { onMounted, reactive, ref, toRefs, watch } from 'vue'

@ -3,8 +3,8 @@
<!-- 过度动画 -->
<transition name="fade">
<!-- 要渲染的组件 -->
<div v-if="refresh">
<component :is="Component" />
<div v-if="refresh" >
<component :is="Component"/>
</div>
</transition>
</router-view>

@ -76,4 +76,4 @@ export default {
name: 'Menu',
}
</script>
<style lang="scss" scoped></style>
<style lang="scss" scoped></style>

@ -9,62 +9,64 @@ import 'nprogress/nprogress.css'
const userStore = useUserStore(pinia)
const usePermissionStore = permissionStore(pinia)
// const whitelist = ['/login', '/404']
router.beforeEach(async (to, form, next) => {
// 进度条开始\
nprogress.configure({ showSpinner: false })
nprogress.start()
// 判断是否登录
if (userStore.token) {
// 登录成功访问登录页则跳转到首页
if (to.path == '/login') {
next({ path: '/' })
} else {
// 登录成功判断是否获取到了用户信息
if (userStore.userName) {
next()
} else {
try {
// 没有获取到用户信息 就获取用户信息 然后放行
await userStore.getUserInfo()
// 获取筛选到的路由
const asyncRouter = await usePermissionStore.getAsyncRoutes(
userStore.routes,
)
// 遍历筛选出来的路由通过addRoute添加到路由表
asyncRouter.forEach((item: any) => {
router.addRoute(item)
})
// 在最后向路由表添加一个404规则
// 切记不要写到路由表内 否者刷新页面会跳转到404页面
router.addRoute({
path: '/:pathMatch(.*)*',
component: () => import('@/views/404/index.vue'),
name: 'Any',
meta: {
title: '任意',
hidden: true,
},
})
next({ ...to, replace: true }) // 这里相当于push到一个页面 不在进入路由拦截
} catch (error) {
// 如果获取用户信息失败了则执行登出操作让重新登录
console.log(error)
userStore.logout()
next({ path: '/login' })
}
}
}
} else {
// 没有token访问登录页放行
if (to.path == '/login') {
next()
} else {
// 访问其他页面则阻止
next({ path: '/login', query: { redirect: to.path } })
}
}
// router.beforeEach(async (to, form, next) => {
// // 进度条开始\
// nprogress.configure({ showSpinner: false })
// nprogress.start()
// // 判断是否登录
// if (userStore.token) {
// // 登录成功访问登录页则跳转到首页
// if (to.path == '/login') {
// next({ path: '/' })
// } else {
// // 登录成功判断是否获取到了用户信息
// if (userStore.userName) {
// next()
// } else {
// try {
// // 没有获取到用户信息 就获取用户信息 然后放行
// await userStore.getUserInfo()
// // 获取筛选到的路由
// const asyncRouter = await usePermissionStore.getAsyncRoutes(
// userStore.routes,
// )
// // 遍历筛选出来的路由通过addRoute添加到路由表
// asyncRouter.forEach((item: any) => {
// router.addRoute(item)
// })
// // 在最后向路由表添加一个404规则
// // 切记不要写到路由表内 否者刷新页面会跳转到404页面
// router.addRoute({
// path: '/:pathMatch(.*)*',
// component: () => import('@/views/404/index.vue'),
// name: 'Any',
// meta: {
// title: '任意',
// hidden: true,
// },
// })
// next({ ...to, replace: true }) // 这里相当于push到一个页面 不在进入路由拦截
// } catch (error) {
// // 如果获取用户信息失败了则执行登出操作让重新登录
// console.log(error)
// userStore.logout()
// next({ path: '/login' })
// }
// }
// }
// } else {
// // 没有token访问登录页放行
// if (to.path == '/login') {
// next()
// } else {
// // 访问其他页面则阻止
// next({ path: '/login', query: { redirect: to.path } })
// }
// }
// })
router.beforeEach((to,form,next) => {
next()
})
router.afterEach((to, form, next) => {
nprogress.done()
})

@ -1,6 +1,6 @@
// 导入路由插件
import { createRouter, createWebHashHistory } from 'vue-router'
import {constantRoute} from './routers.ts'
const routerList = [
{
path: '/login',
@ -14,7 +14,7 @@ const routerList = [
]
const router = createRouter({
history: createWebHashHistory(),
routes: routerList,
routes: [...routerList,...constantRoute],
scrollBehavior() {
return {
left: 0,

@ -1,9 +1,14 @@
<template>
<div>课程点赞</div>
<div>
课程点赞
</div>
</template>
<script lang="ts" setup>
import {} from 'vue'
<script lang='ts' setup>
import { } from 'vue'
</script>
<style lang="scss" scoped></style>
<style lang='scss' scoped>
</style>

@ -1,9 +1,14 @@
<template>
<div>课程收藏</div>
<div>
课程收藏
</div>
</template>
<script lang="ts" setup>
import {} from 'vue'
<script lang='ts' setup>
import { } from 'vue'
</script>
<style lang="scss" scoped></style>
<style lang='scss' scoped>
</style>

@ -1,9 +1,14 @@
<template>
<div>学习过程</div>
<div>
学习过程
</div>
</template>
<script lang="ts" setup>
import {} from 'vue'
<script lang='ts' setup>
import { } from 'vue'
</script>
<style lang="scss" scoped></style>
<style lang='scss' scoped>
</style>

@ -1,9 +1,14 @@
<template>
<div>课程目标</div>
<div>
课程目标
</div>
</template>
<script lang="ts" setup>
import {} from 'vue'
<script lang='ts' setup>
import { } from 'vue'
</script>
<style lang="scss" scoped></style>
<style lang='scss' scoped>
</style>

@ -1,9 +1,288 @@
<script lang="ts" setup>
import { ref, onMounted } from 'vue'
import axios from 'axios'
import courseEdit from './components/courseEdit.vue'
import { getCourseListApi } from '../../api/user/crouse.js'
const courseList = ref([
// id: 1,
// category: '',
// nature: '',
// code: '',
// assessmenttype: '',
// assessmentway: '',
// teachermethod: '',
// teacherway: '',
// description: '',
// name: '',
// credit: '',
// classhours: '',
])
const getCourseList = async () => {
const res = await getCourseListApi()
courseList.value = res.result.list
}
onMounted(() => {
getCourseList()
})
// const courseList = ref([
// {
// id: 1,
// category: '1',
// nature: '1',
// code: '1',
// assessmenttype: '1',
// assessmentway: '1',
// teachermethod: '',
// teacherway: '',
// description: '',
// name: '',
// credit: '',
// classhours: '',
// },
// {
// id: 2,
// category: '1',
// nature: '1',
// code: '1',
// assessmenttype: '1',
// assessmentway: '1',
// teachermethod: '',
// teacherway: '',
// description: '',
// name: '',
// credit: '',
// classhours: '',
// },
// {
// id: 3,
// category: '1',
// nature: '1',
// code: '1',
// assessmenttype: '1',
// assessmentway: '1',
// teachermethod: '',
// teacherway: '',
// description: '',
// name: '',
// credit: '',
// classhours: '',
// },
// {
// id: 4,
// category: '1',
// nature: '1',
// code: '1',
// assessmenttype: '1',
// assessmentway: '1',
// teachermethod: '',
// teacherway: '',
// description: '',
// name: '',
// credit: '',
// classhours: '',
// },
// {
// id: 5,
// category: '1',
// nature: '1',
// code: '1',
// assessmenttype: '1',
// assessmentway: '1',
// teachermethod: '',
// teacherway: '',
// description: '',
// name: '',
// credit: '',
// classhours: '',
// },
// {
// id: 6,
// category: '1',
// nature: '1',
// code: '1',
// assessmenttype: '1',
// assessmentway: '1',
// teachermethod: '',
// teacherway: '',
// description: '',
// name: '',
// credit: '',
// classhours: '',
// },
// {
// id: 7,
// category: '1',
// nature: '1',
// code: '1',
// assessmenttype: '1',
// assessmentway: '1',
// teachermethod: '',
// teacherway: '',
// description: '',
// name: '',
// credit: '',
// classhours: '',
// },
// ])
const drawer = ref()
const onAddCourse = () => {
drawer.value.open({})
}
const onEditCourse = (item) => {
drawer.value.open(item)
}
const onSuccess = () => {
getCourseList()
}
</script>
<template>
<div>课程基本信息</div>
<div class="header">
<div class="btn">
<el-button type="primary" round size="large">全部课程</el-button>
<el-button type="primary" round plain size="large">我的文件夹</el-button>
</div>
<div class="search">
<input type="text" placeholder="搜索课程" />
<i class="el-icon-search"></i>
</div>
</div>
<div class="course">
<ul class="course_list">
<li @click="onAddCourse()">
<img src="" alt="" />
<h2 class="course_name">点击添加课程</h2>
<p class="teacher_name">讲师王兴</p>
<p class="credit">
<span>32</span>
学时|
<span>2.0</span>
学分
</p>
</li>
<li v-for="item in courseList" :key="item.id" @click="onEditCourse(item)">
<img src="" alt="" />
<h2 class="course_name">{{ item.name }}</h2>
<p class="teacher_name">讲师王兴</p>
<p class="credit">
<span>{{ item.classhours }}</span>
学时|
<span>{{ item.credit }}</span>
学分
</p>
</li>
</ul>
</div>
<course-edit ref="drawer" @success="onSuccess"></course-edit>
</template>
<script lang="ts" setup>
import {} from 'vue'
</script>
<style lang="scss" scoped>
.header {
width: 100%;
// height: 100px;
display: flex;
flex-direction: row;
}
.btn {
// display: flex;
width: 50%;
height: 100%;
padding: 10px 45px;
// display: inline;
// height: 40px;
// margin: 20px;
// padding-left: 50px;
}
.search {
width: 50%;
display: flex;
height: 100%;
padding: 10px 0 0 630px;
// flex-direction: row-reverse;
// padding: 0 40px 0;
input {
width: 240px;
height: 40px;
border: 1px solid #dcdcdc;
border-radius: 60px;
font-size: 14px;
}
}
.course {
// display: flex;
// flex: 0 0 25%;
// justify-content: space-between;
// flex-wrap: wrap;
.course_list {
display: flex;
// flex: 0 0 25%;
// justify-content: space-between;
flex-wrap: wrap;
display: grid;
grid-template-columns: repeat(4, 1fr);
column-gap: 50px;
}
li {
margin: 40px 0;
width: 349px;
width: 100%;
height: 297px;
background: white;
transition: all 0.5s;
border-radius: 6px;
// flex: 1; /* */
&:hover {
transform: translate3d(0, -3px, 0);
box-shadow: 0 3px 8px rgb(0 0 0 / 20%);
cursor: pointer;
}
.course_name {
font-family: Inter-Bold;
color: #333;
font-size: 24px;
margin-left: 30px;
margin-top: 10px;
font-weight: bold;
}
img {
background-color: #cccccc;
width: 100%;
height: 178px;
}
p {
margin-left: 30px;
margin-top: 10px;
color: #555555;
font-size: 14px;
padding-top: 12px;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
span {
color: #0052ff;
}
}
<style lang="scss" scoped></style>
h2 {
font-family: Inter-Bold;
color: #333;
font-size: 24px;
margin-left: 30px;
margin-top: 10px;
font-weight: bold;
}
}
}
</style>

@ -0,0 +1,61 @@
<script setup>
import { ref, defineExpose } from 'vue'
import { ElMessage } from 'element-plus'
const dialogVisible = ref(false)
const formModel = ref({
name: '',
desc: '',
})
const formRef = ref()
const rules = {
name: [{ required: true, message: '请输入知识点名称', trigger: 'blur' }],
desc: [{ required: true, message: '请输入知识点简介', trigger: 'blur' }],
}
// open,open
const open = (row) => {
// console.log(row)
formModel.value = { ...row }
dialogVisible.value = true
}
defineExpose({ open })
//
const onSubmit = async () => {
//
await formRef.value.validate()
// formModelid
const isEdit = formModel.value.id
if (isEdit) {
ElMessage.success('编辑成功')
} else {
ElMessage.success('添加成功')
}
dialogVisible.value = false
}
</script>
<template>
<el-dialog
v-model="dialogVisible"
:title="formModel.id ? '编辑知识点' : '新增知识点'"
width="500"
>
<el-form :model="formModel" :rules="rules" ref="formRef">
<el-form-item label="知识点名称" prop="name">
<el-input v-model="formModel.name" placeholder="请输入知识点名称" />
</el-form-item>
<el-form-item label="知识点简介" prop="desc">
<el-input
v-model="formModel.desc"
type="textarea"
placeholder="请输入知识点简介"
/>
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="onSubmit">确认</el-button>
</div>
</template>
</el-dialog>
</template>

@ -0,0 +1,36 @@
<script setup>
import {} from 'vue'
//
defineProps({
title: {
required: true,
type: String,
},
})
</script>
<template>
<el-card class="page-container">
<template #header>
<div class="header">
<span>{{ title }}</span>
<div class="extra">
<!-- 具名插槽定制额外按钮 -->
<slot name="extra"></slot>
</div>
</div>
</template>
<!-- 插槽定制内容使用slot占位 -->
<slot></slot>
</el-card>
</template>
<style lang="scss" scoped>
.page-container {
min-height: 100%;
box-sizing: border-box;
.header {
display: flex;
justify-content: space-between;
align-items: center;
}
}
</style>

@ -0,0 +1,184 @@
<script setup>
import { ElMessage } from 'element-plus'
import { requiredNumber } from 'element-plus/es/components/table-v2/src/common.mjs'
import { ref } from 'vue'
import { editCourseApi } from '../../../api/user/crouse'
import { addCourseApi } from '../../../api/user/crouse'
const formModel = ref({
id: '',
name: '',
category: '',
nature: '',
code: '',
credit: '',
classhours: '',
assessmenttype: '',
assessmentway: '',
teachermethod: '',
teacherway: '',
description: '',
})
const rules = {
name: [
{
required: true,
message: '请输入课程名称',
trigger: 'blur',
},
],
category: [
{
required: true,
message: '请选择课程类别',
trigger: 'change',
},
],
nature: [
{
required: true,
message: '请选择课程性质',
trigger: 'change',
},
],
code: [
{
required: true,
message: '请输入课程编码',
trigger: 'blur',
},
],
credit: [
{
required: true,
message: '请输入课程学分',
trigger: 'blur',
},
{
validator: requiredNumber,
message: '请输入数字',
trigger: 'blur',
},
],
classhours: [
{
required: true,
message: '请输入课程学时',
trigger: 'blur',
},
{
validator: requiredNumber,
message: '请输入数字',
trigger: 'blur',
},
],
assessmenttype: [
{
required: true,
message: '请选择考核类型',
trigger: 'change',
},
],
assessmentway: [
{
required: true,
message: '请选择考核方式',
trigger: 'change',
},
],
}
const formRef = ref()
const visibleDrawer = ref(false)
const open = async (item) => {
formModel.value = { ...item }
visibleDrawer.value = true
}
// open,open
defineExpose({ open })
//
const emit = defineEmits(['success'])
const onSubmit = async () => {
await formRef.value.validate()
const isEdit = formModel.value.id
if (isEdit) {
await editCourseApi(formModel.value)
ElMessage.success('编辑成功')
} else {
await addCourseApi(formModel.value)
ElMessage.success('添加成功')
}
visibleDrawer.value = false
emit('success')
}
</script>
<template>
<el-drawer
v-model="visibleDrawer"
direction="rtl"
:title="formModel.id ? '编辑课程' : '添加课程'"
>
<el-form :model="formModel" :rules="rules" ref="formRef">
<el-form-item label="课程名称" prop="name">
<el-input style="width: 200px" v-model="formModel.name"></el-input>
</el-form-item>
<el-form-item label="课程类别" prop="category">
<el-radio-group v-model="formModel.category">
<el-radio value="major">专业教育</el-radio>
<el-radio value="common">通识教育</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="课程性质" prop="nature">
<el-radio-group v-model="formModel.nature">
<el-radio value="required">必修</el-radio>
<el-radio value="elective">选修</el-radio>
<el-radio value="optional">任修</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="课程编码" prop="code">
<el-input style="width: 200px" v-model="formModel.code"></el-input>
</el-form-item>
<el-form-item label="课程学分" prop="credit">
<el-input style="width: 200px" v-model="formModel.credit"></el-input>
</el-form-item>
<el-form-item label="课程学时" prop="classhours">
<el-input
style="width: 200px"
v-model="formModel.classhours"
></el-input>
</el-form-item>
<el-form-item label="考核类型" prop="assessmenttype">
<el-radio-group v-model="formModel.assessmenttype">
<el-radio value="exam">考试</el-radio>
<el-radio value="assessment">考察</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="考核方式" prop="assessmentway">
<el-radio-group v-model="formModel.assessmentway">
<el-radio value="open">开卷</el-radio>
<el-radio value="close">闭卷</el-radio>
<el-radio value="other">其他</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="教学方法" prop="teachermethod">
<el-input type="textarea" v-model="formModel.teachermethod" />
</el-form-item>
<el-form-item label="教学方式" prop="teacherway">
<el-input type="textarea" v-model="formModel.teacherway" />
</el-form-item>
<el-form-item label="课程简介" prop="description">
<el-input type="textarea" v-model="formModel.description" />
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="visibleDrawer = false" size="large">取消</el-button>
<el-button type="primary" size="large" @click="onSubmit()">
确认
</el-button>
</span>
</template>
</el-drawer>
</template>
<style scoped></style>

@ -1,9 +1,14 @@
<template>
<div>课程图谱</div>
<div>
课程图谱
</div>
</template>
<script lang="ts" setup>
import {} from 'vue'
<script lang='ts' setup>
import { } from 'vue'
</script>
<style lang="scss" scoped></style>
<style lang='scss' scoped>
</style>

@ -1,9 +1,114 @@
<template>
<div>知识点</div>
</template>
<script setup>
import { ref } from 'vue'
import { Delete, Edit } from '@element-plus/icons-vue'
import PageContainer from './components/PageContainer.vue'
import KnowledgeEdit from './components/KnowledgeEdit.vue'
import { ElMessage, ElMessageBox } from 'element-plus'
// const loading = ref(false)
const knowledgeList = [
{
id: '1',
name: '数学',
desc: '数学简介',
},
{
id: '1',
name: '物理',
desc: '物理简介',
},
{
id: '1',
name: '语文',
desc: '语文简介',
},
{
id: '1',
name: '英语',
desc: '英语简介',
},
]
// ref
const dialog = ref()
<script lang="ts" setup>
import {} from 'vue'
const onEditKnowledge = (row) => {
dialog.value.open(row)
}
const onAddKnowledge = () => {
dialog.value.open({})
}
const onDelKnowledge = async () => {
// console.log('1')
await ElMessageBox.confirm('你确认删除该知识点信息吗?', '温馨提示', {
type: 'warning',
confirmButtonText: '确认',
cancelButtonText: '取消',
})
ElMessage({ type: 'success', message: '删除成功' })
}
const params = ref({
pagenum: 1,
pagesize: 2,
})
</script>
<style lang="scss" scoped></style>
<template>
<page-container title="知识点分类">
<!-- v-slot可以替换为# -->
<template #extra>
<el-button type="primary" @click="onAddKnowledge()">新增</el-button>
<el-button type="primary">导出Excel</el-button>
</template>
<el-table
:data="knowledgeList"
style="width: 100%; height: 100%"
:header-cell-style="{ textAlign: 'center' }"
>
<el-table-column align="center" type="index" label="编号" width="100" />
<el-table-column align="center" label="名称" prop="name" />
<el-table-column align="center" label="简介" prop="desc" />
<el-table-column align="center" label="操作">
<!-- 作用域插槽 -->
<!-- rowknowledgeList的每一项 &index下标 -->
<template #default="{ row }">
<el-button
:icon="Edit"
circle
plain
type="primary"
@click="onEditKnowledge(row)"
></el-button>
<el-button
:icon="Delete"
circle
plain
type="danger"
@click="onDelKnowledge(row)"
></el-button>
</template>
</el-table-column>
<template #empty>
<el-empty description="暂无数据"></el-empty>
</template>
</el-table>
<el-pagination
v-model:current-page="params.pagenum"
v-model:page-size="params.pagesize"
:page-sizes="[2, 3, 5, 10]"
:small="small"
:background="true"
layout=" jumper,total, sizes, prev, pager, next"
:total="knowledgeList.length"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
style="margin-top: 20px; justify-content: flex-end"
/>
<knowledge-edit ref="dialog"></knowledge-edit>
</page-container>
</template>
<style lang="scss" scoped>
.el-table {
overflow: hidden;
}
</style>

@ -1,10 +1,6 @@
<template>
<div>home</div>
<svg-icon name="count" width="300px" height="300px" color="#000"></svg-icon>
<div class="box">
<div class="box1"></div>
<div class="box2"></div>
</div>
<svg-icon name="count" width="300px" height="300px" color="pink"></svg-icon>
</template>
<script lang="ts" setup>
@ -17,25 +13,4 @@
// })
</script>
<style lang="scss" scoped>
.box {
width: 500px;
height: 400px;
background-color: skyblue;
display: flex;
// flex-direction: column;
justify-content: space-evenly;
align-items: center;
div {
width: 100px;
height: 100px;
}
.box1 {
background-color: pink;
}
.box2 {
background-color: greenyellow;
}
}
</style>
<style lang="scss" scoped></style>

@ -1,5 +1,6 @@
<template>
<div id="your-element-selector" style="width: 100%; height: 100vh"></div>
<div class="login_container">
<el-row>
<el-col

@ -1,58 +1,14 @@
<template>
<div>
<svg-icon
@click="changePraise()"
v-if="!flog"
name="dianzan"
width="32px"
height="32px"
/>
<svg-icon
@click="changePraise()"
v-else
name="dianzanred"
width="32px"
height="32px"
/>
<!-- <push-button @click="changePraise()"><div class="a"><img src="/src/assets/images/点赞.png" width="100%" height="100%"></div>点赞呀</push-button> -->
<h1>已被点赞{{ praise }}</h1>
</div>
<div>
学习路径推荐
</div>
</template>
<!-- 学习路径推荐 -->
<script lang="ts" setup>
import { ref } from 'vue'
const praise = ref(1000)
const flog = ref(false)
const changePraise = (num = 1) => {
if (!flog.value) {
praise.value++
flog.value = !flog.value
} else {
praise.value--
flog.value = !flog.value
}
}
<script lang='ts' setup>
import { } from 'vue'
</script>
<style lang="scss" scoped>
.a {
width: 50px;
height: 50px;
// display: none;
}
.a:hover {
width: 50px;
height: 50px;
// display: block;
// background-image: url('/src/assets/images/(1).png');
// background-size: 100% 100%;
}
.push-button {
// width: 50px;
// height: 50px;
// background-color: khaki;
// background-image: url('/src/assets/images/.png');
// background-size: 100% 100%;
}
<style lang='scss' scoped>
</style>

@ -1,542 +1,14 @@
<template>
<div>
<!-- <div class="nav">
<div class="icon"></div>
<div class="txt">
<h1>通讯与网络</h1>
<p>张三</p>
</div>
</div> -->
<div class="main">
<div class="title">
<div class="icon"></div>
<div class="right">
<h1>通讯与网络</h1>
<div class="btn">编辑</div>
<p>
本课程讲授通讯与网络的基本概念涉及计算机网络的发展和原理体系结构物理层
数据链路层网络层运输层应用层等计算机网络通讯的整个过程内容包括通讯与网络
的基本概念计算机网络的体
系结构数据通信基础流量控制和拥塞控制TCP/IP
协议簇的基本原理等内容
</p>
<div class="bottom">
<a>总学时 36学时</a>
<a>总学分 2.0</a>
</div>
<div class="bottom">
<a>已分配学时 20学时</a>
<a>章节数 10</a>
</div>
<div class="bottom">
<a>未分配学时 16学时</a>
<a>知识点章节总数 33</a>
</div>
</div>
</div>
<div class="list">
<div class="icon"></div>
<p style="font-size: 20px; margin-bottom: 20px; color: #000">
学习章节
</p>
<el-tree
style="width: 100%; font-size: 15px"
:data="dataSource"
show-checkbox
node-key="id"
default-expand-all
:expand-on-click-node="false"
>
<template #default="{ node, data }">
<span class="custom-tree-node">
<span>{{ node.label }}</span>
<span>
<a @click="append(data)">添加</a>
<a style="margin-left: 8px" @click="remove(node, data)">删除</a>
</span>
</span>
</template>
</el-tree>
</div>
<div>
课程首页
</div>
<div class="sidebar">
<div class="content">
<h3>课程目标</h3>
<div class="btn">了解更多</div>
<a>
课程课程课程课程课程课程课程课程课程课程课程课程课程课程课程课程课程课程课程课程课程课程课程课程课程课程课程课程课程课程课程课程
</a>
</div>
<div class="column" style="">
<div class="icon"></div>
<h3>查看资源</h3>
<ul>
<h2>第一章</h2>
<p>第2小节</p>
<li>
<div class="btn">知识点</div>
<p>知识点详情知识点内容</p>
<div class="icon"></div>
</li>
</ul>
<ul>
<h2>第一章</h2>
<p>第2小节</p>
<li>
<div class="btn">知识点</div>
<p>知识点详情知识点内容</p>
<div class="icon"></div>
</li>
</ul>
<ul>
<h2>第一章</h2>
<p>第2小节</p>
<li>
<div class="btn">知识点</div>
<p>知识点详情知识点内容</p>
<div class="icon"></div>
</li>
</ul>
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
let id = 1000
const append = (data: any) => {
const newChild = { id: id++, label: '请输入新章节', children: [] }
if (!data.children) {
data.children = []
}
data.children.push(newChild)
dataSource.value = [...dataSource.value]
}
const remove = (node: any, data: any) => {
const parent = node.parent
const children: any = parent.data.children || parent.data
const index = children.findIndex((d: any) => d.id === data.id)
children.splice(index, 1)
dataSource.value = [...dataSource.value]
}
// const renderContent = (
// h:any,
// {
// node,
// data,
// store,
// }: {
// node: any
// data: any
// store: any['store']
// }
// ) => {
// return h(
// 'span',
// {
// class: 'custom-tree-node',
// },
// h('span', null, node.label),
// h(
// 'span',
// null,
// h(
// 'a',
// {
// onClick: () => append(data),
// },
// 'Append '
// ),
// h(
// 'a',
// {
// style: 'margin-left: 8px',
// onClick: () => remove(node, data),
// },
// 'Delete'
// )
// )
// )
// }
<script lang='ts' setup>
import { } from 'vue'
const dataSource = ref<any>([
{
id: 1,
label: '01/基本概念',
children: [
{
id: 4,
label: '1-1 基本概念',
children: [
{
id: 9,
label: '1-1-1 基本概念',
},
{
id: 10,
label: '1-1-2 基本概念',
},
],
},
],
},
{
id: 2,
label: '02/章节名',
children: [
{
id: 5,
label: '2-1 章节名字',
},
{
id: 6,
label: '2-2 章节名字',
},
],
},
{
id: 3,
label: '03/章节名字',
children: [
{
id: 7,
label: '3-1 章节名字',
},
{
id: 8,
label: '3-2 章节名字',
},
],
},
{
id: 3,
label: '04/章节名字',
children: [
{
id: 9,
label: '4-1 章节名字',
},
{
id: 10,
label: '4-2 章节名字',
},
],
},
])
</script>
<style lang="scss" scoped>
ul {
list-style: none;
}
a {
text-decoration: none;
}
body {
/* 宽度占浏览器可视区域的宽度 */
width: 100vm;
/* height: 1500px; */
background-color: #f6f6f6;
}
.nav {
width: 100%;
height: 60px;
background-color: #797a82;
}
.nav .icon {
width: 10%;
height: 90%;
margin-top: 5px;
float: left;
background-image: url('/src/assets/images/kc.jpg');
background-size: 100% 100%;
border-radius: 20px 20px 20px 20px;
}
.nav .txt {
width: 10%;
height: 100%;
float: left;
margin-left: 15px;
background-color: #5577ff;
// border-left: 1px solid #252529
}
.nav h1 {
font-size: 18px;
line-height: 35px;
font-weight: bolder;
}
.nav p {
// font-size: 18px;
line-height: 25px;
color: #252529;
}
.main {
width: 75%;
height: 900px;
float: left;
// background-color: bisque
}
.main .title {
width: 90%;
margin: auto;
height: 25%;
// background-color: blueviolet
}
.main .title .icon {
width: 34%;
height: 80%;
margin-top: 20px;
background-color: antiquewhite;
float: left;
background-image: url('/src/assets/images/kc.jpg');
background-size: 100% 100%;
border-radius: 20px 20px 20px 20px;
}
.main .title .right {
width: 61%;
height: 80%;
margin-left: 30px;
margin-top: 20px;
// background-color: antiquewhite;
float: left;
}
.main .title .right h1 {
height: 20px;
color: #5577ff;
font-size: 20px;
font-weight: bolder;
letter-spacing: 1px;
// background-color: antiquewhite;
float: left;
}
.main .title .right p {
height: 20px;
font-size: 12px;
line-height: 16px;
color: #797a82;
padding-top: 7px;
float: left;
}
.main .title .right .bottom {
width: 30.6%;
height: 30%;
float: left;
margin-left: 10px;
margin-top: 16.5%;
// background-color: #5577FF
}
.main .title .right a {
display: flex;
justify-content: space-between;
height: 28px;
font-size: 12px;
color: #0d0d11;
// padding-top: 50px;
// float: left;
}
.main .title .right .btn {
width: 14%;
height: 16%;
font-size: 15px;
background-color: #5577ff;
color: #f6f6f6;
text-align: center;
line-height: 25px;
border-radius: 14px 14px 14px 14px;
float: left;
margin-left: 58%;
}
.main .title .right .btn:hover {
background-color: #185cd2;
}
.main .list {
width: 100%;
height: 57.3%;
margin: auto;
padding: 20px 10px;
background-color: #ffffff;
border-radius: 20px 20px 20px 20px;
}
.main .list .icon {
width: 3%;
height: 5%;
margin-top: px;
// background-color: antiquewhite;
float: left;
background-image: url('/src/assets/images/rwd.png');
background-size: 100% 100%;
// border-radius: 20px 20px 20px 20px;
}
.sidebar {
width: 22%;
height: 800px;
float: left;
margin-left: 20px;
// background-color: rgb(84, 50, 9)
}
.sidebar .content {
width: 100%;
height: 20%;
border-radius: 14px 14px 14px 14px;
border-left: 4px solid #5577ff;
background-color: #ffffff;
box-shadow: 1px 1px 1px 1px rgba(0, 0, 0, 0.1);
}
.sidebar .content h3 {
color: #0d0d11;
height: 30px;
font-size: 15px;
font-weight: bolder;
margin-left: 15px;
float: left;
line-height: 40px;
}
.sidebar .content .btn {
width: 30%;
height: 13%;
font-size: 11px;
background-color: #ebecfc;
color: #4f86e5;
text-align: center;
font-weight: bolder;
float: right;
line-height: 20px;
margin-top: 10px;
border-radius: 14px 14px 14px 14px;
}
.sidebar .content .btn:hover {
background-color: #185cd2;
color: white;
}
.sidebar .content a {
color: #797a82;
height: 50px;
width: 90%;
font-size: 15px;
line-height: 20px;
margin-left: 15px;
float: left;
margin-top: 5px;
}
.sidebar .column {
width: 100%;
height: 70%;
margin-top: 20px;
border-radius: 14px 14px 14px 14px;
background-color: #ffffff;
box-shadow: 1px 1px 1px 0.1px rgba(0.2, 1, 1, 0.2);
}
.sidebar .column .icon {
width: 13%;
height: 5%;
float: left;
margin-left: 10px;
margin-top: 10px;
background-image: url('/src/assets/images/ck.png');
background-size: 100% 100%;
}
.sidebar .column h3 {
color: #16161b;
height: 30px;
font-size: 15px;
font-weight: bolder;
margin-left: 15px;
float: left;
line-height: 45px;
}
.sidebar .column ul {
width: 90%;
height: 28%;
float: left;
margin-top: 10px;
margin-left: 12px;
text-decoration: none;
// border-left:1px solid #505053 ;
// background-color: #4F86E5
}
.sidebar .column ul h2 {
color: #0d0d11;
height: 30px;
font-size: 14px;
font-weight: bolder;
// margin-left: 15px;
float: left;
line-height: 20px;
}
.sidebar .column ul p {
color: #252529;
height: 30px;
font-size: 11px;
// font-weight:bolder;
margin-left: 15px;
float: left;
line-height: 20px;
}
.sidebar .column ul li {
width: 90%;
height: 80%;
float: left;
margin-left: 20px;
text-decoration: none;
border-left: 1px solid #d4d4df;
// background-color: #9fb8e3
}
.sidebar .column ul li .btn {
width: 30%;
height: 15%;
float: left;
margin-left: 20px;
color: #ebecfc;
line-height: 20px;
font-size: 11px;
text-align: center;
border-radius: 5px 5px 5px 5px;
background-color: #56df7d;
}
.sidebar .column ul li p {
line-height: 30px;
height: 10%;
font-size: 11.5px;
float: left;
margin-left: 22px;
text-decoration: none;
color: #0d0d11;
}
.sidebar .column ul li .icon {
width: 89%;
height: 50%;
margin-top: 20px;
float: left;
margin-left: 20px;
background-image: url('/src/assets/images/zy.jpg');
background-size: 100% 100%;
}
// .app-container {
// padding: 30px 140px;
// font-size: 14px;
// }
<style lang='scss' scoped>
// .tree-manager {
// width: 50px;
// display: inline-block;
// margin: 10px;
// }
::v-deep .custom-tree-node {
flex: 1;
display: flex;
justify-content: space-between;
padding-right: 30px;
}
</style>

@ -1,353 +1,14 @@
<template>
<div>
<div class="header">
<h1>课程报告</h1>
<div class="content">
<div class="box">
<div class="icon">
<img
src="/src/assets/images/小旗子.png"
width="100%"
height="100%"
/>
</div>
<p>学习进度统计</p>
</div>
<a style="color: #d81e06">Learning progress statistics</a>
<b style="color: #d81e06">40</b>
</div>
<div class="content">
<div class="box">
<div class="icon">
<img
src="/src/assets/images/知识点.png"
width="100%"
height="100%"
/>
</div>
<p>知识点数统计</p>
</div>
<a style="color: #ff8b00">Knowledge point statistics</a>
<b style="color: #ff8b00">30</b>
</div>
<div class="content">
<div class="box">
<div class="icon">
<img
src="/src/assets/images/统计计算.png"
width="100%"
height="100%"
/>
</div>
<p>学习人数统计</p>
</div>
<a style="margin-top: 25px; margin-left: 60px; color: #4b81d7">
Student count
</a>
<b style="color: #4b81d7">0</b>
</div>
<div class="content">
<div class="box">
<div class="icon">
<img src="/src/assets/images/课程.png" width="100%" height="100%" />
</div>
<p>学习课程统计</p>
</div>
<a style="margin-top: 25px; margin-left: 60px; color: #08b762">
Course statistics
</a>
<b style="color: #08b762">10</b>
</div>
</div>
<div class="search">
<form>
<input type="text" placeholder="输入文本进行搜索" />
<div class="icon">
<img src="/src/assets/images/搜索.png" width="100%" height="100%" />
</div>
<!-- <input type="image" src="/src/assets/images/搜索.png" > -->
</form>
</div>
<div class="main">
<el-table
:data="dataSource"
style="
display: flex;
width: 100%;
flex-direction: row;
justify-content: space-around;
"
>
<el-table-column
prop="course"
label="课程名称"
width="180"
></el-table-column>
<el-table-column
prop="date"
label="知识点个数"
width="180"
></el-table-column>
<el-table-column
prop="time"
label="知识点学时"
width="180"
></el-table-column>
<el-table-column
prop="proportion"
label="知识点占比"
width="180"
></el-table-column>
<el-table-column
prop="student"
label="学习人数统计"
width="180"
></el-table-column>
<el-table-column
prop="credet"
label="课程学分"
width="180"
></el-table-column>
</el-table>
<div>
课程报告
</div>
</div>
<div class="download">点击此按钮导出报告</div>
<div class="a"></div>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
const dataSource = ref([
{
course: '数学',
date: '50',
time: '24h',
proportion: '89%',
student: '220人',
credet: 2,
},
{
course: '数学',
date: '50',
time: '24h',
proportion: '89%',
student: '220人',
credet: 2,
},
{
course: '数学',
date: '50',
time: '24h',
proportion: '89%',
student: '220人',
credet: 2,
},
{
course: '数学',
date: '50',
time: '24h',
proportion: '89%',
student: '220人',
credet: 2,
},
{
course: '数学',
date: '50',
time: '24h',
proportion: '89%',
student: '220人',
credet: 2,
},
{
course: '数学',
date: '50',
time: '24h',
proportion: '89%',
student: '220人',
credet: 2,
},
{
course: '数学',
date: '50',
time: '24h',
proportion: '89%',
student: '220人',
credet: 2,
},
{
course: '数学',
date: '50',
time: '24h',
proportion: '89%',
student: '220人',
credet: 2,
},
{
course: '数学',
date: '50',
time: '24h',
proportion: '89%',
student: '220人',
credet: 2,
},
])
</script>
<style lang="scss" scoped>
ul {
list-style: none;
}
<script lang='ts' setup>
import { } from 'vue'
a {
text-decoration: none;
}
body {
/* 宽度占浏览器可视区域的宽度 */
width: 100vm;
/* height: 1500px; */
background-color: #f6f6f6;
}
.header {
width: 95%;
height: 250px;
margin: auto;
// background-color: aquamarine
}
.header h1 {
font-size: 20px;
color: #000;
}
.header .content {
width: 20%;
height: 65%;
// background-color: bisque;
background-color: #ffffff;
border-radius: 10px 10px 10px 10px;
float: left;
margin-left: 40px;
margin-top: 20px;
}
.header .content .icon {
width: 24.5%;
height: 62%;
float: left;
// margin-left: 1px;
margin-top: 13px;
}
.header .content .box {
width: 65%;
height: 30%;
// background-color: #f6f6f6;
margin: auto;
margin-top: 10px;
}
.header .content a {
font-size: 14.5px;
height: 10%;
float: left;
margin-left: 20px;
margin-top: 20px;
// font-weight:bolder;
}
.header .content b {
font-size: 30px;
height: 10%;
margin: auto;
float: left;
margin-top: 15px;
margin-left: 100px;
font-weight: bolder;
}
.header .content p {
color: #000;
font-size: 15px;
height: 10%;
float: left;
// text-align: center;
margin-top: 20px;
margin-left: 3px;
font-weight: bolder;
}
.search {
width: 75%;
height: 30px;
background-color: paleturquoise;
margin: auto;
border-radius: 10px 10px 10px 10px;
margin-top: 20px;
}
.search input {
width: 100%;
height: 40px;
text-indent: 5px;
font-size: 16px;
/* border: none; */
// text-align: center;
background-color: #fffefe;
border-radius: 10px 10px 10px 10px;
border: 1px solid #75aade;
/* border-bottom: 1px solid #ddd; */
outline: none;
// margin: 12px auto;
}
.search .icon {
width: 40px;
height: 35px;
position: relative;
top: -37px;
left: 93%;
}
.search .icon:hover {
width: 41px;
height: 36px;
}
// .search form{
// width: 190px;
// height: 30px;
// border: 1px solid #C1C1C1;
// border-radius: 3px;
// }
.main {
width: 90%;
height: 450px;
// background-color: #75aade;
// border-radius: 10px 10px 10px 10px;
margin: auto;
margin-top: 50px;
}
</script>
// ptf
<style lang='scss' scoped>
.download {
width: 15%;
height: 24px;
float: right;
margin-right: 60px;
margin-top: 20px;
// margin-bottom: 20px;
// margin-left: 0px;
font-size: 14px;
text-align: center;
line-height: 23px;
color: #75aade;
background-color: #ffffff;
box-shadow: 1px 1px 1px 0.1px rgba(0.2, 1, 1, 0.2);
border-radius: 10px 10px 10px 10px;
}
.download:hover {
background-color: #75aade;
color: #ffffff;
}
.a {
width: 100%;
float: left;
height: 40px;
}
.el-table_header-wrapper {
display: flex;
flex-direction: row;
justify-content: space-around;
}
</style>

File diff suppressed because it is too large Load Diff

@ -1,9 +1,14 @@
<template>
<div>知识点学习</div>
<div>
知识点学习
</div>
</template>
<script lang="ts" setup>
import {} from 'vue'
<script lang='ts' setup>
import { } from 'vue'
</script>
<style lang="scss" scoped></style>
<style lang='scss' scoped>
</style>

Loading…
Cancel
Save