Compare commits

...

8 Commits
live ... main

Author SHA1 Message Date
07a5f956f2 fix(study): 修复视频播放结束逻辑和定时器清理问题
修复视频播放结束判断条件,增加对播放进度的验证
添加定时器清理逻辑防止内存泄漏
2025-08-15 15:52:41 +08:00
2704846056 fix(study): 优化视频定时器处理并添加路由离开清理
确保在组件销毁和路由离开时都清除视频定时器,避免内存泄漏。简化视频当前时间获取逻辑,移除不必要的条件判断。
2025-08-15 14:47:29 +08:00
fc801620c0 refactor(study): 移除调试日志并优化视频时间获取逻辑
在ExamTest组件中移除已注释的调试日志
在courseDetail组件中增加视频元素存在性检查,避免潜在错误
2025-08-15 14:13:46 +08:00
f7eca311fa feat(安全): 添加加密解密功能并更新考试组件
- 新增crypto-js依赖用于数据加密解密
- 添加decrypt.js工具文件实现AES解密功能
- 修改Exam.vue组件使用加密接口获取考试数据
- 清理main.js中多余空行并格式化代码
2025-08-15 10:49:17 +08:00
efb38e1106 fix: 更新生产环境API地址
将生产环境的BASE_API地址从"https://admins.jiangtang360.com/api"修改为"http://admin.jiangtang360.com/api",确保API调用的正确性。
2025-08-05 17:38:33 +08:00
d050df6f21 chore: 升级项目依赖和构建工具,迁移至Webpack 5.x
主要变更包括:
1. 更新Babel配置,使用@babel/preset-env和@babel/plugin-transform-object-rest-spread。
2. 升级Webpack及相关插件,使用MiniCssExtractPlugin替代ExtractTextPlugin。
3. 更新package-lock.json和package.json,调整依赖版本。
4. 修改README.md,更新项目简介和环境要求。
5. 代码格式优化和错误处理增强,提升构建和开发体验。
2025-08-04 16:27:52 +08:00
68153d45a1 fix: 从main分支移除liveView.vue文件,该文件应只存在于live分支 2025-08-01 18:16:14 +08:00
54a3a5cf9f feat: 新增在线课堂直播页面组件及功能实现
实现在线课堂直播页面,包含以下功能:
1. 视频直播展示及控制(全屏、音量调节)
2. 教师摄像头和学生摄像头分屏显示
3. 聊天消息发送与接收
4. 课程信息展示
5. 水印显示及动画效果
6. 状态管理(未开始/直播中/已结束)
7. 响应式布局及样式优化
2025-08-01 17:46:07 +08:00
21 changed files with 29419 additions and 8324 deletions

View File

@ -1,13 +1,9 @@
{
"presets": [
["env", { "modules": false }],
"stage-2",
["es2015", { "modules": false }]
["@babel/preset-env", { "modules": false }]
],
"plugins": ["transform-object-rest-spread",["component", [
{
"plugins": [["@babel/plugin-transform-object-rest-spread", {}], ["component", {
"libraryName": "mint-ui",
"style": true
}
]]]
}]]
}

View File

@ -2,7 +2,7 @@
## 项目简介
JT360是一个基于Vue.js 2.x的前端项目使用Webpack 3.x作为构建工具。项目集成了Mint-UI组件库支持移动端开发。
JT360是一个基于Vue.js 2.x的前端项目使用Webpack 5.x作为构建工具。项目集成了Mint-UI组件库支持移动端开发。
## 技术栈
@ -10,19 +10,22 @@ JT360是一个基于Vue.js 2.x的前端项目使用Webpack 3.x作为构建工
- **Vue Router 3.0.1** - 路由管理
- **Vuex 3.0.1** - 状态管理
- **Mint-UI 2.2.13** - 移动端UI组件库
- **Webpack 3.6.0** - 构建工具
- **Webpack 5.88.2** - 构建工具
- **Axios 0.17.1** - HTTP客户端
- **Sass** - CSS预处理器
- **buffer@6.0.3**、**process@0.11.10** - Node.js核心模块polyfill
## 环境要求
### Node.js版本要求
**严格要求使用 Node.js 12.22.12 版本**
support Node.js 18.x 版本
> 注意使用Node.js 18.x版本时可能会遇到node-sass弃用警告和pkcs7包兼容性警告但不影响项目运行。
```bash
# 检查Node.js版本
node -v
# 应该显示: v12.22.12
# 推荐显示: v18.12.1 或更高版本
```
### 其他要求
@ -39,21 +42,36 @@ cd jt360front
### 2. 安装依赖
```bash
npm install
# 或者使用yarn(推荐使用yarn)
yarn install
npm install --legacy-peer-deps
# 或者使用yarn
# yarn install
```
### 3. 开发环境运行
```bash
yarn dev
npm run dev
# 或者使用yarn
# yarn dev
```
### 4. 生产环境构建
```bash
yarn build
npm run build
# 或者使用yarn
# yarn build
```
## Webpack 5 升级说明
项目已从Webpack 3.x升级到Webpack 5.x主要解决了以下问题
1. 添加了Node.js核心模块如Buffer、process的polyfill
2. 配置了fallback解析路径
3. 使用ProvidePlugin全局提供对象
升级后可能存在的警告:
- node-sass弃用警告建议未来迁移到sass/sass-embedded
- pkcs7包引擎版本不兼容警告建议未来更新此包
## 项目结构
```
@ -85,7 +103,10 @@ jt360front/
## 开发注意事项
1. **Node.js版本**必须使用12.22.12版本,其他版本可能导致依赖包兼容性问题
1. **Node.js版本**支持Node.js 18.x版本
2. **浏览器兼容性**支持现代浏览器不支持IE8及以下版本
3. **移动端适配**项目主要针对移动端开发使用了Mint-UI组件库
4. **依赖安装**:建议使用`npm install --legacy-peer-deps`安装依赖以避免兼容性问题
2. **浏览器兼容性**支持现代浏览器不支持IE8及以下版本
3. **移动端适配**项目主要针对移动端开发使用了Mint-UI组件库
@ -102,15 +123,18 @@ jt360front/
## 常见问题
### Q: 为什么必须使用Node.js 12.22.12
A: 项目依赖的某些包如node-sass 4.12.0对Node.js版本有严格要求使用其他版本可能导致编译错误。
### Q: 为什么使用Node.js 18.x版本会出现警告
A: 主要是node-sass和pkcs7包的兼容性问题这些警告不影响项目运行。未来计划迁移到sass/sass-embedded并更新pkcs7包。
### Q: 如何解决依赖安装冲突?
A: 建议使用`npm install --legacy-peer-deps`命令安装依赖。
### Q: 如何切换Node.js版本
A: 推荐使用nvmNode Version Manager来管理Node.js版本
```bash
# 安装指定版本
nvm install 12.22.12
nvm use 12.22.12
nvm install 18.12.1
nvm use 18.12.1
```
## 联系方式

View File

@ -18,17 +18,24 @@ rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => {
if (err) throw err
webpack(webpackConfig, (err, stats) => {
spinner.stop()
if (err) throw err
process.stdout.write(stats.toString({
colors: true,
modules: false,
children: false, // If you are using ts-loader, setting this to true will make TypeScript errors show up during build.
if (err) {
console.log(chalk.red(' Webpack configuration error:'))
console.error(err)
process.exit(1)
}
process.stdout.write(stats.toString({ colors: true,
modules: true,
children: true,
chunks: false,
chunkModules: false
}) + '\n\n')
if (stats.hasErrors()) {
console.log(chalk.red(' Build failed with errors.\n'))
console.log(chalk.red(' Error details:'))
stats.toJson().errors.forEach(error => {
console.error(error)
})
process.exit(1)
}

View File

@ -1,7 +1,7 @@
'use strict'
const path = require('path')
const config = require('../config')
const ExtractTextPlugin = require('extract-text-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const packageConfig = require('../package.json')
exports.assetsPath = function (_path) {
@ -45,10 +45,7 @@ exports.cssLoaders = function (options) {
// Extract CSS when that option is specified
// (which is the case during production build)
if (options.extract) {
return ExtractTextPlugin.extract({
use: loaders,
fallback: 'vue-style-loader'
})
return [MiniCssExtractPlugin.loader].concat(loaders)
} else {
return ['vue-style-loader'].concat(loaders)
}

View File

@ -2,7 +2,10 @@
const path = require('path')
const utils = require('./utils')
const config = require('../config')
const vueLoaderConfig = require('./vue-loader.conf')
const { VueLoaderPlugin } = require('vue-loader')
const webpack = require('webpack')
const Buffer = require('buffer').Buffer
const CopyWebpackPlugin = require('copy-webpack-plugin')
function resolve (dir) {
return path.join(__dirname, '..', dir)
@ -20,21 +23,27 @@ module.exports = {
filename: '[name].js',
publicPath: process.env.NODE_ENV === 'production'
? config.build.assetsPublicPath
: config.dev.assetsPublicPath
: config.dev.assetsPublicPath,
clean: true
},
resolve: {
extensions: ['.js', '.vue', '.json'],
alias: {
'vue$': 'vue/dist/vue.esm.js',
'@': resolve('src'),
},
fallback: {
crypto: require.resolve('crypto-browserify'),
stream: require.resolve('stream-browserify'),
buffer: require.resolve('buffer/'),
vm: require.resolve('vm-browserify')
}
},
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader',
options: vueLoaderConfig
loader: 'vue-loader'
},
{
test: /\.js$/,
@ -68,16 +77,21 @@ module.exports = {
}
]
},
node: {
// prevent webpack from injecting useless setImmediate polyfill because Vue
// source contains it (although only uses it if it's native).
setImmediate: false,
// prevent webpack from injecting mocks to Node native modules
// that does not make sense for the client
dgram: 'empty',
fs: 'empty',
net: 'empty',
tls: 'empty',
child_process: 'empty'
}
plugins: [
new VueLoaderPlugin(),
new webpack.ProvidePlugin({
process: 'process/browser',
Buffer: ['buffer', 'Buffer'],
})
]
// Node.js polyfills are no longer included by default in Webpack 5
// If needed, use resolve.fallback or providePlugin
// node: {
// setImmediate: false,
// dgram: 'empty',
// fs: 'empty',
// net: 'empty',
// tls: 'empty',
// child_process: 'empty'
// }
}

View File

@ -2,18 +2,18 @@
const utils = require('./utils')
const webpack = require('webpack')
const config = require('../config')
const merge = require('webpack-merge')
const { merge } = require('webpack-merge')
const path = require('path')
const baseWebpackConfig = require('./webpack.base.conf')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const portfinder = require('portfinder')
const HOST = process.env.HOST
const PORT = process.env.PORT && Number(process.env.PORT)
const devWebpackConfig = merge(baseWebpackConfig, {
mode: 'development',
module: {
rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap, usePostCSS: true })
},
@ -22,35 +22,36 @@ const devWebpackConfig = merge(baseWebpackConfig, {
// these devServer options should be customized in /config/index.js
devServer: {
clientLogLevel: 'warning',
client: {
logging: 'warn',
overlay: config.dev.errorOverlay
? { warnings: false, errors: true }
: false,
},
historyApiFallback: {
rewrites: [
{ from: /.*/, to: path.posix.join(config.dev.assetsPublicPath, 'index.html') },
],
},
hot: true,
contentBase: false, // since we use CopyWebpackPlugin.
static: false, // since we use CopyWebpackPlugin.
compress: true,
host: HOST || config.dev.host,
port: PORT || config.dev.port,
open: config.dev.autoOpenBrowser,
overlay: config.dev.errorOverlay
? { warnings: false, errors: true }
: false,
publicPath: config.dev.assetsPublicPath,
proxy: config.dev.proxyTable,
quiet: true, // necessary for FriendlyErrorsPlugin
watchOptions: {
watchFiles: {
options: {
poll: config.dev.poll,
},
disableHostCheck:true
},
allowedHosts: 'all'
},
plugins: [
new webpack.DefinePlugin({
'process.env': require('../config/dev.env')
}),
new webpack.HotModuleReplacementPlugin(),
new webpack.NamedModulesPlugin(), // HMR shows correct file names in console on update.
new webpack.NoEmitOnErrorsPlugin(),
// https://github.com/ampedandwired/html-webpack-plugin
new HtmlWebpackPlugin({
@ -59,13 +60,17 @@ const devWebpackConfig = merge(baseWebpackConfig, {
inject: true
}),
// copy custom static assets
new CopyWebpackPlugin([
new CopyWebpackPlugin({
patterns: [
{
from: path.resolve(__dirname, '../static'),
to: config.dev.assetsSubDirectory,
ignore: ['.*']
globOptions: {
ignore: ['**/.*']
}
])
}
]
})
]
})
@ -80,16 +85,6 @@ module.exports = new Promise((resolve, reject) => {
// add port to devServer config
devWebpackConfig.devServer.port = port
// Add FriendlyErrorsPlugin
devWebpackConfig.plugins.push(new FriendlyErrorsPlugin({
compilationSuccessInfo: {
messages: [`Your application is running here: http://${devWebpackConfig.devServer.host}:${port}`],
},
onErrors: config.dev.notifyOnErrors
? utils.createNotifierCallback()
: undefined
}))
resolve(devWebpackConfig)
}
})

View File

@ -3,59 +3,69 @@ const path = require('path')
const utils = require('./utils')
const webpack = require('webpack')
const config = require('../config')
const merge = require('webpack-merge')
const { merge } = require('webpack-merge')
const baseWebpackConfig = require('./webpack.base.conf')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const ExtractTextPlugin = require('extract-text-webpack-plugin')
const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')
const TerserPlugin = require('terser-webpack-plugin')
const env = require('../config/prod.env')
const webpackConfig = merge(baseWebpackConfig, {
module: {
rules: utils.styleLoaders({
sourceMap: config.build.productionSourceMap,
extract: true,
usePostCSS: true
})
rules: utils.styleLoaders({ sourceMap: config.build.productionSourceMap, extract: true, usePostCSS: true })
},
devtool: config.build.productionSourceMap ? config.build.devtool : false,
output: {
path: config.build.assetsRoot,
filename: utils.assetsPath('js/[name].[chunkhash].js'),
chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
filename: utils.assetsPath('js/[name].[contenthash].js'),
chunkFilename: utils.assetsPath('js/[id].[contenthash].js')
},
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
terserOptions: {
compress: {
warnings: false
}
},
parallel: true
}),
new CssMinimizerPlugin({
minimizerOptions: {
preset: [
'default',
{
discardComments: { removeAll: true },
},
],
},
})
],
splitChunks: {
chunks: 'all',
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendor',
chunks: 'all'
}
}
},
runtimeChunk: 'single'
},
plugins: [
// http://vuejs.github.io/vue-loader/en/workflow/production.html
new webpack.DefinePlugin({
'process.env': env
}),
new UglifyJsPlugin({
uglifyOptions: {
compress: {
warnings: false
}
},
sourceMap: config.build.productionSourceMap,
parallel: true
}),
// extract css into its own file
new ExtractTextPlugin({
new MiniCssExtractPlugin({
filename: utils.assetsPath('css/[name].[contenthash].css'),
// Setting the following option to `false` will not extract CSS from codesplit chunks.
// Their CSS will instead be inserted dynamically with style-loader when the codesplit chunk has been loaded by webpack.
// It's currently set to `true` because we are seeing that sourcemaps are included in the codesplit bundle as well when it's `false`,
// increasing file size: https://github.com/vuejs-templates/webpack/issues/1110
allChunks: true,
}),
// Compress extracted CSS. We are using this plugin so that possible
// duplicated CSS from different components can be deduped.
new OptimizeCSSPlugin({
cssProcessorOptions: config.build.productionSourceMap
? { safe: true, map: { inline: false } }
: { safe: true }
chunkFilename: utils.assetsPath('css/[id].[contenthash].css')
}),
// generate dist index.html with correct asset hash for caching.
// you can customize output by editing /index.html
@ -71,51 +81,23 @@ const webpackConfig = merge(baseWebpackConfig, {
// more options:
// https://github.com/kangax/html-minifier#options-quick-reference
},
// necessary to consistently work with multiple chunks via CommonsChunkPlugin
chunksSortMode: 'dependency'
chunksSortMode: 'auto'
}),
// keep module.id stable when vendor modules does not change
new webpack.HashedModuleIdsPlugin(),
// enable scope hoisting
new webpack.optimize.ModuleConcatenationPlugin(),
// split vendor js into its own file
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
minChunks (module) {
// any required modules inside node_modules are extracted to vendor
return (
module.resource &&
/\.js$/.test(module.resource) &&
module.resource.indexOf(
path.join(__dirname, '../node_modules')
) === 0
)
}
}),
// extract webpack runtime and module manifest to its own file in order to
// prevent vendor hash from being updated whenever app bundle is updated
new webpack.optimize.CommonsChunkPlugin({
name: 'manifest',
minChunks: Infinity
}),
// This instance extracts shared chunks from code splitted chunks and bundles them
// in a separate chunk, similar to the vendor chunk
// see: https://webpack.js.org/plugins/commons-chunk-plugin/#extra-async-commons-chunk
new webpack.optimize.CommonsChunkPlugin({
name: 'app',
async: 'vendor-async',
children: true,
minChunks: 3
}),
new webpack.ids.HashedModuleIdsPlugin(),
// copy custom static assets
new CopyWebpackPlugin([
new CopyWebpackPlugin({
patterns: [
{
from: path.resolve(__dirname, '../static'),
to: config.build.assetsSubDirectory,
ignore: ['.*']
globOptions: {
ignore: ['**/.*']
}
])
}
]
})
]
})

View File

@ -1,9 +1,8 @@
'use strict'
const merge = require('webpack-merge')
const { merge } = require('webpack-merge')
const prodEnv = require('./prod.env')
module.exports = merge(prodEnv, {
NODE_ENV: '"development"',
// BASE_API: '"http://spadmin.jiangtang360.com/api"'
BASE_API: '"http://admin.jiangtang360.com/api"',
// BASE_API: '"http://zywsadmin.jiangtang360.com/api"'

View File

@ -36,8 +36,7 @@ module.exports = {
*/
// https://webpack.js.org/configuration/devtool/#development
// devtool: 'cheap-module-eval-source-map',
devtool: '#source-map',
devtool: 'eval-cheap-module-source-map',
// If you have problems debugging vue-files in devtools,
// set this to false - it *may* help
@ -66,7 +65,7 @@ module.exports = {
productionSourceMap: true,
// https://webpack.js.org/configuration/devtool/#production
devtool: '#source-map',
devtool: 'source-map',
// Gzip off by default as many popular static hosts such as
// Surge or Netlify already gzip all static assets for you.

View File

@ -1,7 +1,6 @@
'use strict'
module.exports = {
NODE_ENV: '"production"',
// BASE_API: '"http://spadmin.jiangtang360.com/api"'
BASE_API: '"https://admins.jiangtang360.com/api"'
BASE_API: '"http://admin.jiangtang360.com/api"'
// BASE_API: '"http://zywsadmin.jiangtang360.com/api"'
}

28002
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -5,9 +5,9 @@
"author": "王觉贤 <615297896@qq.com>",
"private": true,
"scripts": {
"dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js --host 0.0.0.0",
"dev": "webpack serve --config build/webpack.dev.conf.js --host 0.0.0.0",
"start": "npm run dev",
"build": "node build/build.js"
"build": "node build/build.js --display-error-details"
},
"dependencies": {
"@fortawesome/fontawesome-svg-core": "^6.2.0",
@ -19,6 +19,7 @@
"console": "^0.7.2",
"core-js": "^3.39.0",
"crypto": "^1.0.1",
"crypto-js": "^4.2.0",
"cssnano": "^4.1.10",
"exif-js": "^2.3.0",
"font-awesome": "^4.7.0",
@ -34,9 +35,11 @@
"vuex": "^3.0.1"
},
"devDependencies": {
"@babel/core": "^7.22.9",
"@babel/preset-env": "^7.22.9",
"autoprefixer": "^7.1.2",
"babel-helper-vue-jsx-merge-props": "^2.0.3",
"babel-loader": "^7.1.1",
"babel-loader": "^8.3.0",
"babel-plugin-component": "^1.1.0",
"babel-plugin-syntax-jsx": "^6.18.0",
"babel-plugin-transform-object-rest-spread": "^6.26.0",
@ -45,35 +48,42 @@
"babel-preset-env": "^1.7.0",
"babel-preset-es2015": "^6.24.1",
"babel-preset-stage-2": "^6.22.0",
"buffer": "^6.0.3",
"chalk": "^2.0.1",
"copy-webpack-plugin": "^4.0.1",
"copy-webpack-plugin": "^11.0.0",
"crypto-browserify": "^3.12.1",
"css-loader": "^2.1.1",
"extract-text-webpack-plugin": "^3.0.0",
"css-minimizer-webpack-plugin": "^7.0.2",
"file-loader": "^1.1.4",
"friendly-errors-webpack-plugin": "^1.6.1",
"html-webpack-plugin": "^2.30.1",
"html-webpack-plugin": "^5.5.3",
"mini-css-extract-plugin": "^2.7.6",
"node-notifier": "^5.1.2",
"node-sass": "^4.12.0",
"node-sass": "^9.0.0",
"optimize-css-assets-webpack-plugin": "^2.0.0",
"ora": "^1.2.0",
"portfinder": "^1.0.13",
"postcss-import": "^11.0.0",
"postcss-loader": "^2.0.8",
"postcss-url": "^7.2.1",
"process": "^0.11.10",
"rimraf": "^2.6.0",
"sass-loader": "^6.0.6",
"semver": "^5.3.0",
"shelljs": "^0.7.6",
"stream-browserify": "^3.0.0",
"terser-webpack-plugin": "^5.3.9",
"uglifyjs-webpack-plugin": "^1.0.0",
"url-loader": "^1.1.2",
"vue-loader": "^13.3.0",
"vm-browserify": "^1.1.2",
"vue-loader": "^15.10.1",
"vue-style-loader": "^3.0.1",
"vue-template-compiler": "^2.5.2",
"webpack": "^3.6.0",
"webpack": "^5.88.2",
"webpack-bundle-analyzer": "^3.3.2",
"webpack-cli": "^3.3.1",
"webpack-dev-server": "^2.9.4",
"webpack-merge": "^4.1.0",
"webpack-cli": "^5.1.4",
"webpack-dev-server": "^4.15.1",
"webpack-merge": "^5.9.0",
"weixin-js-sdk": "^1.3.2"
},
"engines": {

View File

@ -116,7 +116,8 @@
</div>
</div>
</mt-popup>
<mt-popup v-model="popupVisible2" popup-transition="popup-fade" style="background-color: #5e5e5e; border-radius: 20px;">
<mt-popup v-model="popupVisible2" popup-transition="popup-fade"
style="background-color: #5e5e5e; border-radius: 20px;">
<div style=" top: 5px; font-size: 20px; font-weight: bold; margin: 20px 0; color: white;">请选择要考试的课程</div>
<div style=" margin: 30px; width: 250px;" v-for="(item, index) in courseData" :key="index">
<mt-button @click="btn_courseID(item.id)" type="default" class=""
@ -143,6 +144,7 @@ import { getStore } from "@/utils/storage";
import { Toast } from "mint-ui";
import { MessageBox } from "mint-ui";
import WXTake from "../study/weixinTake.vue";
import { decrypt } from "@/utils/decrypt";
export default {
name: "LiuYan",
components: { Back, WXTake },
@ -267,19 +269,20 @@ export default {
var current_time_stamp = new Date().getTime();
//
this.getData("/Question/getExamQuestions", {
// this.getData("/Question/getExamQuestions", {
this.getData("/Question/getExamQuestionsSecurity", {
token: getStore("token"),
course_id: this.courseID,
}).then(
(data) => {
// console.log("data=>",data.data.exam_data);
if (data.code == 1) {
const questions = decrypt(data.data);
let _this = this;
this.is_start = 1;
this.id = data.data.id;
this.questions = data.data.question_data;
this.current_question_data = data.data.question_data[0];
this.exam_data = data.data.exam_data;
this.id = questions.id;
this.questions = questions.question_data;
this.current_question_data = questions.question_data[0];
this.exam_data = questions.exam_data;
this.title = "正式考试";
this.monishow = false;
var count = 1;
@ -873,6 +876,7 @@ export default {
align-items: center;
z-index: 1000;
}
.mask-content {
background: white;
padding: 30px;
@ -881,6 +885,7 @@ export default {
width: 80%;
max-width: 400px;
}
.mask-content p {
margin-bottom: 20px;
font-size: 16px;

View File

@ -590,7 +590,7 @@ export default {
},
mounted() {
console.log(this.loginInfo);
// console.log(this.loginInfo);
this.start();
},

View File

@ -161,6 +161,7 @@
<div v-for="(item, index) in questions" :key="index" @click="goQ(index)" v-bind:class="{
error: item.is_wrong == 1 && current_question != index,
active: current_question == index,
done: item.response != '' && !is_end
}">
{{ index + 1 }}
</div>
@ -253,6 +254,7 @@ export default {
}
},
toggleTabs(tabText) {
// this.is_end = false;
this.choose = tabText;
if (tabText == 3) {
let is_lead = getStore("is_lead1");
@ -341,8 +343,8 @@ export default {
//
function timer() {
// console.log("");
let curTime = document.getElementById("video").currentTime;
let apartTime = curTime - _this.current_sign;
if (apartTime > 2 && _this.section[_this.choose_section_index].is_end != 1) {
document.getElementById("video").currentTime = _this.current_sign;
@ -411,7 +413,9 @@ export default {
//2s
//
let duration = document.getElementById("video").duration;
if (curTime >= (duration - 2)) {
// console.log(curTime, _this.current_sign, duration, "-----")
if (curTime >= (duration - 2) && _this.current_sign >= (duration - 10)) {
if (_this.last30sTimer && _this.section[_this.choose_section_index].is_end != 1) {
// console.log("211111111111111111");
_this.last30sTimer = false;
@ -431,22 +435,36 @@ export default {
_this.current_sign = _this.record;
Toast("从上次记录的地方开始播放");
setTimeout(function () {
//
if (_this.video_timer) {
clearInterval(_this.video_timer);
}
_this.video_timer = setInterval(timer, 100);
}, 1000);
}
function onPlayerEnded() {
const duration = document.getElementById("video").duration;
// console.log(duration, "");
if (_this.current_sign >= duration - 10) {
document
.getElementById("video")
.removeEventListener("ended", onPlayerEnded, false);
_this.onPlayerEnded();
}
}
console.log("视频播放进度:", _this.record);
if (_this.record > 0.1) {
_this.current_sign = _this.record;
document.getElementById("video").addEventListener("play", plays, false);
} else {
// vd.play();
//
if (_this.video_timer) {
clearInterval(_this.video_timer);
}
_this.video_timer = setInterval(timer, 100);
}
//
@ -852,6 +870,16 @@ export default {
}
},
},
beforeRouteLeave(to, from, next) {
//
// console.log(":", this.video_timer);
if (this.video_timer) {
clearInterval(this.video_timer);
this.video_timer = null; //
}
next();
},
beforeDestroy() {
if (this.video_timer) {
clearInterval(this.video_timer);
@ -1103,6 +1131,10 @@ export default {
&.error {
background: red;
}
&.done {
background: #1fff00;
}
}
}

View File

@ -191,7 +191,7 @@ export default {
type: type,
}).then(
(data) => {
if (data.code == 1) {
if (data.code == 1 && data.data != null) {
let _this = this;
// console.log(data.data)
this.questions = data.data;

View File

@ -74,7 +74,7 @@
[
{
key:1,
img:'../../../static/img/shezhi.png',
img:'/static/img/shezhi.png',
desc:'修改密码',
border:false,
link:'/user/changepwd'

View File

@ -25,7 +25,6 @@ import "regenerator-runtime/runtime";
let wx = require('weixin-js-sdk')
Vue.config.productionTip = false
// mintui模块
Vue.component(Button.name, Button)
Vue.component(Swipe.name, Swipe);

29
src/utils/decrypt.js Normal file
View File

@ -0,0 +1,29 @@
import CryptoJS from 'crypto-js'
const SECRET_KEY = 'mIS*fo4T2ioFSw91Flaovn@ofiq89Fqe';
export function decrypt(encryptedResponse) {
// 1. Base64解码
const iv = CryptoJS.enc.Base64.parse(encryptedResponse.iv)
const payload = CryptoJS.enc.Base64.parse(encryptedResponse.payload)
// 2. 执行AES解密
const decrypted = CryptoJS.AES.decrypt(
{ ciphertext: payload },
CryptoJS.enc.Utf8.parse(SECRET_KEY),
{
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
}
)
// 3. 转为UTF-8字符串并解析JSON
try {
return JSON.parse(decrypted.toString(CryptoJS.enc.Utf8))
} catch (e) {
console.error("解密失败: ", e)
return null
}
}

231
webpack-upgrade-plan.md Normal file
View File

@ -0,0 +1,231 @@
# Webpack 3 升级到 Webpack 5 详细计划
## 升级背景
当前项目使用 Webpack 3.6.0,需要升级到 Webpack 5 以支持 Node.js 18并提升构建性能和安全性。
## 升级前准备
1. 备份项目代码和 `package.json` 文件
2. 确保已安装 Node.js 18+(当前计划使用版本)
3. 了解 Webpack 3 与 Webpack 5 的主要差异
## 升级步骤
### 1. 卸载旧依赖
```bash
npm uninstall webpack webpack-cli webpack-dev-server webpack-merge extract-text-webpack-plugin
```
### 2. 安装新依赖
```bash
npm install webpack@5.88.2 webpack-cli@5.1.4 webpack-dev-server@4.15.1 webpack-merge@5.9.0 mini-css-extract-plugin@2.7.6 --save-dev
npm install html-webpack-plugin@5.5.3 --save-dev
npm install vue-loader@15.10.1 --save-dev
```
### 3. 更新 package.json 脚本
修改 `package.json` 中的 scripts 部分:
```json
{
"scripts": {
"dev": "webpack serve --config build/webpack.dev.conf.js --host 0.0.0.0",
"build": "node build/build.js"
}
}
```
### 4. 修改 Webpack 配置文件
#### 4.1 修改 webpack.base.conf.js
- 添加 VueLoaderPlugin
- 更新 module.rules 配置
- 调整输出配置
#### 4.2 修改 webpack.dev.conf.js
- 更新 devServer 配置
- 修改插件配置
#### 4.3 修改 webpack.prod.conf.js
- 替换 extract-text-webpack-plugin 为 mini-css-extract-plugin
- 更新优化配置
- 移除过时插件
### 5. 解决可能的兼容性问题
- 处理 Babel 配置
- 更新其他 loader 版本
- 解决依赖冲突
## 主要变化点
1. Webpack 5 内置更多功能,减少对第三方插件的依赖
2. 开发服务器配置变化 (webpack-dev-server -> webpack serve)
3. 提取 CSS 的插件变化 (extract-text-webpack-plugin -> mini-css-extract-plugin)
4. 模块解析和优化配置的变化
5. 缓存机制改进
## 可能遇到的问题及解决方案
1. **Node.js 版本兼容问题**:确保使用 Node.js 18+
2. **插件不兼容**:逐一替换为 Webpack 5 兼容版本
3. **配置语法变化**:更新配置文件以符合 Webpack 5 语法
4. **依赖冲突**:使用 npm ls 检查并解决冲突
## 测试计划
1. 升级后运行 `npm run dev` 测试开发环境
2. 运行 `npm run build` 测试生产构建
3. 检查应用功能是否正常
4. 验证构建输出文件大小和性能
## 实际升级问题及解决方案
在实际升级过程中,我们遇到了以下问题并成功解决:
### 1. Node.js 核心模块未定义问题 (Buffer, process)
**问题描述**:升级到 Webpack 5 后,浏览器中出现 `Buffer is not defined``process is not defined` 错误。
**原因**Webpack 5 不再自动 polyfill Node.js 核心模块,需要手动添加。
**解决方案**
1. 安装必要的 polyfill 包:
```bash
npm install buffer@6.0.3 process@0.11.10 vm-browserify@1.1.2 --save
```
2. 在 webpack.base.conf.js 中添加以下配置:
```javascript
const webpack = require('webpack');
module.exports = {
// ... 其他配置
resolve: {
fallback: {
buffer: require.resolve('buffer/'),
process: require.resolve('process/'),
vm: require.resolve('vm-browserify')
}
},
plugins: [
// ... 其他插件
new webpack.ProvidePlugin({
Buffer: ['buffer', 'Buffer'],
process: 'process/browser'
})
]
};
```
### 2. Node.js 18 与 node-sass 兼容性问题
**问题描述**:在 Node.js 18 环境下,使用旧版本 node-sass 导致编译错误。
**原因**node-sass 4.x 不兼容 Node.js 18。
**解决方案**
1. 升级 node-sass 到最新版本:
```bash
npm install node-sass@9.0.0 --save-dev --legacy-peer-deps
```
2. 使用 `--legacy-peer-deps` 标志解决与 webpack 5 的依赖冲突。
> 注意node-sass 已被弃用,建议未来迁移到 sass 或 sass-embedded。
### 3. pkcs7 包引擎版本不兼容警告
**问题描述**:安装依赖时出现 pkcs7 包要求 node@^0.10 的警告。
**原因**:项目依赖的 pkcs7 包版本过旧,与 Node.js 18 不兼容。
**解决方案**
- 目前可以忽略此警告,不影响项目运行。
- 建议未来更新此包到兼容版本。
### 4. 依赖安装冲突
**问题描述**:安装新依赖时出现多个包版本冲突。
**原因**:不同包对同一个依赖的版本要求不一致。
**解决方案**
- 使用 `npm install --legacy-peer-deps` 命令安装依赖:
```bash
npm install --legacy-peer-deps
```
### 5. webpack-dev-server 配置变化
**问题描述**:升级后开发服务器无法正常启动。
**原因**webpack-dev-server 4.x 配置方式有较大变化。
**解决方案**
1. 更新 webpack.dev.conf.js 中的 devServer 配置:
```javascript
devServer: {
host: '0.0.0.0',
port: 8080,
client: {
overlay: { warnings: false, errors: true },
},
historyApiFallback: true,
proxy: {
'/api': {
target: 'http://sz-test.shengzhevictor.com',
changeOrigin: true
}
}
}
```
2. 更新 package.json 中的 dev 脚本:
```json
{
"scripts": {
"dev": "webpack serve --config build/webpack.dev.conf.js --host 0.0.0.0"
}
}
```
### 6. resolve.fallback 配置引号问题
**问题描述**Webpack 5 配置验证错误,提示 resolve.fallback 配置中的属性名不能带引号。
**原因**Webpack 5 对配置格式有更严格的要求resolve.fallback 中的属性名应该是标识符而非字符串。
**解决方案**
修改 webpack.base.conf.js 文件,移除 resolve.fallback 配置中各属性名的单引号:
```javascript
resolve: {
fallback: {
crypto: require.resolve('crypto-browserify'),
stream: require.resolve('stream-browserify'),
buffer: require.resolve('buffer/'),
process: require.resolve('process/'),
vm: require.resolve('vm-browserify')
}
}
```
### 7. devtool 配置格式问题
**问题描述**Webpack 5 配置验证错误,提示 configuration.devtool 不符合模式 "^(inline-|hidden-|eval-)?(nosources-)?(cheap-(module-)?)?source-map(-debugids)?$"
**原因**Webpack 5 对 devtool 配置格式有严格要求,不再支持以 "#" 开头的格式。
**解决方案**
修改 config/index.js 文件,将 build.devtool 的值从 "#source-map" 改为 "source-map"
```javascript
build: {
// ... 其他配置
devtool: 'source-map',
// ... 其他配置
}
```
## 升级总结
1. 成功将 Webpack 从 3.6.0 升级到 5.88.2
2. 解决了 Node.js 18 兼容性问题,使项目能够在现代 Node.js 环境下运行
3. 添加了必要的 Node.js 核心模块 polyfill
4. 解决了依赖冲突和插件兼容性问题
5. 更新了构建配置以符合 Webpack 5 语法
虽然升级过程中遇到了一些挑战,但通过逐一解决问题,最终成功完成了升级,为项目后续的维护和性能优化奠定了基础。

8975
yarn.lock

File diff suppressed because it is too large Load Diff