Compare commits
3 Commits
b44aaf3849
...
4fe89b0398
Author | SHA1 | Date |
---|---|---|
lijiaqi | 4fe89b0398 | 6 months ago |
Alan | 5085e5a38a | 6 months ago |
lijiaqi | f7614c883d | 6 months ago |
26 changed files with 4508 additions and 2928 deletions
@ -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', // 禁止不必要的转义字符 |
||||
}, |
||||
/* 继承已有的规则 */ |
||||
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', // 对模板中的自定义组件强制执行属性命名样式 |
||||
}, |
||||
} |
||||
// 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 |
@ -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> |
@ -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
@ -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,14 +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 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' |
||||
<style lang="scss" scoped> |
||||
.header { |
||||
width: 100%; |
||||
// height: 100px; |
||||
display: flex; |
||||
flex-direction: row; |
||||
} |
||||
|
||||
</script> |
||||
.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; |
||||
|
||||
<style lang='scss' scoped> |
||||
span { |
||||
color: #0052ff; |
||||
} |
||||
} |
||||
|
||||
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() |
||||
// 看formModel传的是否有id |
||||
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,14 +1,9 @@ |
||||
<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,14 +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: '物理简介', |
||||
}, |
||||
|
||||
<script lang='ts' setup> |
||||
import { } from 'vue' |
||||
{ |
||||
id: '1', |
||||
name: '语文', |
||||
desc: '语文简介', |
||||
}, |
||||
{ |
||||
id: '1', |
||||
name: '英语', |
||||
desc: '英语简介', |
||||
}, |
||||
] |
||||
// 通过ref绑定弹窗 |
||||
const dialog = ref() |
||||
|
||||
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> |
||||
<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="操作"> |
||||
<!-- 作用域插槽 --> |
||||
<!-- row:knowledgeList的每一项 &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> |
||||
|
Loading…
Reference in new issue