Merge branch 'develop' of https://gitee.com/siwa-team/dawa-vue into develop

This commit is contained in:
18571350067 2022-01-10 21:07:34 +08:00
commit a55496bddb
36 changed files with 11899 additions and 49061 deletions

View File

@ -1,5 +1,24 @@
{ {
"printWidth": 120, "printWidth": 120,
"tabWidth": 2,
"singleQuote": true,
"trailingComma": "none",
"semi": false, "semi": false,
"singleQuote": true "wrap_line_length": 220,
"wrap_attributes": "false",
"proseWrap": "auto",
"arrowParens": "avoid",
"bracketSpacing": true,
"jsxBracketSameLine": true,
"useTabs": false,
"eslintIntegration":true,
"overrides": [
{
"files": ".prettierrc",
"options": {
"parser": "json"
}
}
],
"endOfLine": "auto"
} }

39423
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -13,9 +13,11 @@
"dependencies": { "dependencies": {
"@ant-design-vue/pro-layout": "^0.3.4", "@ant-design-vue/pro-layout": "^0.3.4",
"@antv/data-set": "^0.10.2", "@antv/data-set": "^0.10.2",
"@icon-park/vue": "^1.3.5",
"ant-design-vue": "^1.7.7", "ant-design-vue": "^1.7.7",
"axios": "^0.19.0", "axios": "^0.19.0",
"core-js": "^3.1.2", "core-js": "^3.1.2",
"dplayer": "^1.26.0",
"draftjs-to-html": "^0.9.1", "draftjs-to-html": "^0.9.1",
"enquire.js": "^2.1.6", "enquire.js": "^2.1.6",
"file-saver": "^2.0.5", "file-saver": "^2.0.5",

View File

@ -19,7 +19,7 @@
* 因此UEditor提供了针对不同页面的编辑器可单独配置的根路径具体来说在需要实例化编辑器的页面最顶部写上如下代码即可当然需要令此处的URL等于对应的配置 * 因此UEditor提供了针对不同页面的编辑器可单独配置的根路径具体来说在需要实例化编辑器的页面最顶部写上如下代码即可当然需要令此处的URL等于对应的配置
* window.UEDITOR_HOME_URL = "/xxxx/xxxx/"; * window.UEDITOR_HOME_URL = "/xxxx/xxxx/";
*/ */
var URL = window.UEDITOR_HOME_URL || getUEBasePath(); var URL = window.UEDITOR_HOME_URL || getUEBasePath()
/** /**
* 配置项主体注意此处所有涉及到路径的配置别遗漏URL变量 * 配置项主体注意此处所有涉及到路径的配置别遗漏URL变量

View File

@ -12,16 +12,40 @@ import { i18nRender } from '@/locales'
export default { export default {
data() { data() {
return { return {}
}
}, },
computed: { computed: {
locale() { locale() {
// //
const { title } = this.$route.meta const { title } = this.$route.meta
title && (setDocumentTitle(`${i18nRender(title)} - ${domTitle}`)) title && setDocumentTitle(`${i18nRender(title)} - ${domTitle}`)
return this.$i18n.getLocaleMessage(this.$store.getters.lang).antLocale return this.$i18n.getLocaleMessage(this.$store.getters.lang).antLocale
} }
} }
} }
</script> </script>
<style lang="less">
.modal-title {
font-size: 16px;
font-weight: bold;
color: #333;
display: flex;
align-items: center;
margin-top: 15px;
&::before {
content: '';
display: inline-block;
width: 4px;
height: 16px;
background: #1890ff;
margin-right: 3px;
}
}
.i-icon{
display: flex;
align-items: center;
justify-content: center;
}
</style>

View File

@ -29,7 +29,6 @@ export function dictionaryDel (params) {
}) })
} }
export function dictionaryPage(params) { export function dictionaryPage(params) {
console.log(params)
return request({ return request({
url: dictionaryApi.page, url: dictionaryApi.page,
method: 'get', method: 'get',

BIN
src/assets/img/demo1.jpeg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

View File

@ -0,0 +1,85 @@
<template>
<div>
<div class="sub-title">单选题</div>
<div class="options">
<a-row :gutter="[16, 16]">
<a-anchor :affix="false">
<a-col v-for="(item, index) in 12" :key="index" :span="4">
<div class="option-item flex-center" :class="{ 'option-item-active': index === 0 }">
<a-anchor-link :href="`#type1-${index}`" :title="index + 1"></a-anchor-link>
</div>
</a-col>
</a-anchor>
</a-row>
</div>
<div class="sub-title">多选题</div>
<div class="options">
<a-row :gutter="[16, 16]">
<a-anchor :affix="false">
<a-col v-for="(item, index) in 6" :key="index" :span="4">
<div class="option-item flex-center" :class="{ 'option-item-active': index === 0 }">
<a-anchor-link :href="`#type2-${index}`" :title="index + 1"></a-anchor-link>
</div>
</a-col>
</a-anchor>
</a-row>
</div>
<div class="sub-title">判断题</div>
<div class="options">
<a-row :gutter="[16, 16]">
<a-anchor :affix="false">
<a-col v-for="(item, index) in 6" :key="index" :span="4">
<div class="option-item flex-center" :class="{ 'option-item-active': index === 0 }">
<a-anchor-link :href="`#type3-${index}`" :title="index + 1"></a-anchor-link>
</div>
</a-col>
</a-anchor>
</a-row>
</div>
<div class="sub-title">填空题</div>
<div class="options"></div>
</div>
</template>
<script>
import { Anchor } from 'ant-design-vue'
export default {
props: {
pref: Object
},
components: {
'a-anchor': Anchor,
'a-anchor-link': Anchor.Link
}
}
</script>
<style lang="less" scoped>
.sub-title {
font-size: 16px;
font-weight: bold;
color: #333;
margin: 10px 0;
}
.option-item {
background: #f9f9f9;
height: 48px;
width: 100%;
font-size: 16px;
color: #333;
border-radius: 4px;
}
.option-item-active {
background: #1890ff;
color: #fff;
::v-deep .ant-anchor-link-title {
color: #fff;
}
}
::v-deep .ant-anchor-link {
padding: 0;
}
</style>

View File

@ -0,0 +1,129 @@
<template>
<div class="question-item">
<div class="question-title">
<span>{{ questionIndex || 1 }}</span>
<span>({{ type | QuestionTypeFormat }})</span>
<span v-html="title"></span>
</div>
<div class="options-box">
<ul class="answer-list">
<li :class="{'success-li' : index == 2}" v-for="(item, index) in options" :key="index">
<span>{{ optionKeys[index] }}</span>{{ item.label }}
</li>
</ul>
</div>
<div class="flex-center justify-between" style="margin-top: 10px;">
<div style="flex: 1;">
<a-button @click="analysisVisible = false" style="padding: 0;" v-if="analysisVisible" type="link">收起答题解析</a-button>
<a-button @click="analysisVisible = true" style="padding: 0;" v-else type="link">展开答题解析</a-button>
</div>
<div style="flex: 1;"></div>
</div>
<div class="box" v-show="analysisVisible">
<div class="flex-center analysis">
<div class="analysis-label">
<div class="flex-center" style="height: 30px;">
<a-tag color="blue" >统计</a-tag>
</div>
</div>
<div class="analysis-value">答题时间44全站正确率47%易错项D</div>
</div>
<div class="flex-center analysis">
<div class="analysis-label">
<a-tag color="blue" style="margin-top: 6px;">解析</a-tag>
</div>
<div class="analysis-value" style="color: #333;">第一步本题考查新发展理念第二步十三五规划建议提出的创新协调绿色开放共享五大发展理念集中反映了我们党对经济社会发展规律认识的深化是建议的精髓和主线也是本次全会的亮点和重大贡献创新发展注重的是解决发展动力问题我国创新能力不强科技发展水平总体不高科技对经济社会发展的支撑能力不足科技对经济增长的贡献率远低于发达国家水平协调发展注重的是解决发展不平衡问题我国发展不协调是一个长期存在的问题突出表现在区域城乡经济和社会物质文明和精神文明经济建设和国防建设等关系上绿色发展注重的是解决人与自然和谐共生问题我国资源约束趋紧环境污染严重生态系统退化的问题十分严峻开放发展注重的是解决发展内外联动问题现在的问题不是要不要对外开放而是如何提高对外开放的质量和发展的内外联动性共享发展注重的是解决社会公平正义问题我国经济发展的蛋糕不断做大但分配不公问题比较突出收入差距城乡区域公共服务水平差距较大在共享改革发展成果上无论是实际情况还是制度设计都还有不完善的地方所以①③④正确因此选择C选项</div>
</div>
</div>
</div>
</template>
<script>
export default {
props: {
questionIndex: {
type: [Number],
default: 1
}, //
type: {
type: [String, Number], // 1: , 2: , 3: , 4: , 5:
default: 1
}
},
data () {
return {
analysisVisible: true,
optionKeys: ['A', 'B', 'C', 'D', 'E'],
radioStyle: {
display: 'block',
height: '30px',
lineHeight: '30px'
},
title: '党的十九大报告指出 ,要推动社会主义文化繁荣兴盛,建设社会主义文化强国。下列关于推动社会主义文化繁荣兴盛的说法不正确的是?',
answer: null, // , : String/Number, : Array
options: [
{ label: '是提高国家硬实力的必然要求', value: 1 },
{ label: '是新时代坚持和发展中国特色社会主义的必然要求', value: 2 },
{ label: '是实现中华民族伟大复兴中国梦的必然要求', value: 3 },
{ label: '是实现人民对美好生活向往的必然要求', value: 4 }
]
}
}
}
</script>
<style lang="less" scoped>
.question-item {
margin-top: 15px;
font-size: 15px;
}
.question-title {
margin-bottom: 10px;
color: #333;
}
.options-box {
padding-left: 30px;
}
.answer-list{
margin: 0;
padding: 0;
li{
line-height: 2;
}
.success-li{
color: #52c41a;
}
}
.box{
width: 100%;
}
.draw-enter-active, .draw-leave-active {
transition: all 1s ease;
}
.draw-enter, .draw-leave-to {
height: 0;
}
.analysis{
justify-content: center;
align-items: stretch;
}
.analysis-label{
flex: 0 0 40px;
flex-shrink: 0;
}
.analysis-value{
flex: 1;
flex-shrink: 0;
display: flex;
align-items: center;
font-size: 15px;
color: #000;
vertical-align: top;
line-height: 2;
}
</style>

View File

@ -0,0 +1,104 @@
<template>
<div class="question-item">
<div class="question-title">
<span>{{index || 1}}</span>
<span>({{ type | QuestionTypeFormat }})</span>
<span v-html="title"></span>
</div>
<div class="options-box">
<!-- 单选题选项 -->
<template v-if="type == 1">
<a-radio-group v-model="answer">
<a-radio v-for="(item, index) in options" :key="index" :style="radioStyle" :value="item.value">
<span>{{ optionKeys[index] }}</span>{{ item.label }}
</a-radio>
</a-radio-group>
</template>
<!-- 多选题选项 -->
<template v-if="type == 2">
<a-checkbox-group v-model="answer">
<a-col :span="24" v-for="(item, index) in options" :key="index">
<a-checkbox :value="item.value" :style="radioStyle">
<span>{{ optionKeys[index] }}</span>{{ item.label }}
</a-checkbox>
</a-col>
</a-checkbox-group>
</template>
<!-- 判断题选项 -->
<template v-if="type == 3">
<a-radio-group v-model="answer">
<a-radio :style="radioStyle" :value="1"> <span>A</span>正确</a-radio>
<a-radio :style="radioStyle" :value="2"> <span>B</span>错误</a-radio>
</a-radio-group>
</template>
<!-- 填空题 -->
<template v-if="type == 4">
<a-row :gutter="50" style="font-size: 14px;">
<a-col :span="12" class="flex-center" style="margin-bottom: 10px;"
><span class="flex-center nowrap">填空1:&nbsp;&nbsp;</span> <a-input placeholder="请填写答案"
/></a-col>
<a-col :span="12" class="flex-center" style="margin-bottom: 10px;"
><span class="flex-center nowrap">填空2:&nbsp;&nbsp;</span> <a-input placeholder="请填写答案"
/></a-col>
<a-col :span="12" class="flex-center"
><span class="flex-center nowrap">填空3:&nbsp;&nbsp;</span> <a-input placeholder="请填写答案"
/></a-col>
<a-col :span="12" class="flex-center"
><span class="flex-center nowrap">填空4:&nbsp;&nbsp;</span> <a-input placeholder="请填写答案"
/></a-col>
</a-row>
</template>
<!-- 简单题 -->
<template v-if="type == 5">
<div style="font-size: 14px;padding-bottom: 5px;">答案区:</div>
<a-row>
<a-textarea placeholder="请填写答案" :rows="4" />
</a-row>
</template>
</div>
</div>
</template>
<script>
export default {
props: {
index: Number, //
type: {
type: [String, Number], // 1: , 2: , 3: , 4: , 5:
default: 1
}
},
data() {
return {
optionKeys: ['A', 'B', 'C', 'D', 'E'],
radioStyle: {
display: 'block',
height: '30px',
lineHeight: '30px'
},
title: '请问2021年是什么年?',
answer: null, // , : String/Number, : Array
options: [
{ label: '牛年', value: 1 },
{ label: '蛇年', value: 2 },
{ label: '鸡年', value: 3 },
{ label: '虎年', value: 4 }
]
}
}
}
</script>
<style lang="less" scoped>
.question-item {
margin-top: 15px;
font-size: 15px;
}
.question-title {
margin-bottom: 10px;
color: #333;
}
.options-box {
padding-left: 30px;
}
</style>

View File

@ -14,6 +14,7 @@
msg: '', msg: '',
id: 'ueditor' + Math.random(), id: 'ueditor' + Math.random(),
editorConfig: { editorConfig: {
lang: 'zh-cn',
UEDITOR_HOME_URL: '/static/plugins/ueditor/', UEDITOR_HOME_URL: '/static/plugins/ueditor/',
serverUrl: '/dawa/sys/ueditor/config', serverUrl: '/dawa/sys/ueditor/config',
}, },
@ -43,6 +44,7 @@
immediate: true, immediate: true,
handler: function (config) { handler: function (config) {
const defaults = { const defaults = {
lang: 'zh-cn',
UEDITOR_HOME_URL: '/static/plugins/ueditor/', UEDITOR_HOME_URL: '/static/plugins/ueditor/',
serverUrl: '/dawa/sys/ueditor/config', serverUrl: '/dawa/sys/ueditor/config',
} }

View File

@ -16,9 +16,9 @@ export default {
primaryColor: '#1890ff', // primary color of ant design primaryColor: '#1890ff', // primary color of ant design
layout: 'sidemenu', // nav menu position: `sidemenu` or `topmenu` layout: 'sidemenu', // nav menu position: `sidemenu` or `topmenu`
contentWidth: 'Fluid', // layout of content: `Fluid` or `Fixed`, only works when layout is topmenu contentWidth: 'Fluid', // layout of content: `Fluid` or `Fixed`, only works when layout is topmenu
fixedHeader: false, // sticky header fixedHeader: true, // sticky header
fixSiderbar: false, // sticky siderbar fixSiderbar: true, // sticky siderbar
colorWeak: false, colorWeak: true,
menu: { menu: {
locale: true locale: true
}, },

View File

@ -107,3 +107,31 @@ ol {
text-align: left; text-align: left;
} }
} }
// 公用样式
.text-center {
text-align: center;
}
.text-right {
text-align: right;
}
.margin-top {
margin-top: 15px;
}
.flex-center{
display: flex;
align-items: center;
justify-content: center;
}
.justify-between{
justify-content: space-between;
}
.nowrap{
white-space: nowrap;
}

View File

@ -35,8 +35,14 @@
} }
.ant-layout-sider { .ant-layout-sider {
flex: 0 0 230px !important; flex: 0 0 230px;
max-width: 230px !important; max-width: 230px;
min-width: 230px !important; min-width: 230px;
width: 230px !important; width: 230px;
}
.ant-pro-basicLayout-content{
height: calc(100vh - 95px) !important;
overflow-x: hidden;
overflow-y: auto;
} }

View File

@ -14,9 +14,9 @@
<template v-slot:rightContentRender> <template v-slot:rightContentRender>
<right-content :top-menu="settings.layout === 'topmenu'" :is-mobile="isMobile" :theme="settings.theme" /> <right-content :top-menu="settings.layout === 'topmenu'" :is-mobile="isMobile" :theme="settings.theme" />
</template> </template>
<template v-slot:footerRender> <!-- <template v-slot:footerRender>
<global-footer /> <global-footer />
</template> </template> -->
<router-view /> <router-view />
</pro-layout> </pro-layout>
</template> </template>

View File

@ -10,6 +10,7 @@ import i18n from './locales'
import { VueAxios } from './utils/request' import { VueAxios } from './utils/request'
import ProLayout, { PageHeaderWrapper } from '@ant-design-vue/pro-layout' import ProLayout, { PageHeaderWrapper } from '@ant-design-vue/pro-layout'
import themePluginConfig from '../config/themePluginConfig' import themePluginConfig from '../config/themePluginConfig'
import '@/utils/prototype'
import bootstrap from './core/bootstrap' import bootstrap from './core/bootstrap'
import './core/lazy_use' import './core/lazy_use'

View File

@ -11,6 +11,30 @@ Vue.filter('NumberFormat', function (value) {
return intPartFormat return intPartFormat
}) })
Vue.filter('QuestionTypeFormat', function(value) {
let result = ''
switch (Number(value)) {
case 1:
result = '单选题'
break
case 2:
result = '多选题'
break
case 3:
result = '判断题'
break
case 4:
result = '填空题'
break
case 5:
result = '简答题'
break
default:
break
}
return result
})
Vue.filter('AmountFormat', function(val) { Vue.filter('AmountFormat', function(val) {
if (!val) { if (!val) {
return '0.00' return '0.00'

6
src/utils/prototype.js vendored Normal file
View File

@ -0,0 +1,6 @@
import Vue from 'vue'
import store from '@/store/index'
Vue.prototype.$getDictByCode = function(code) {
console.log('dictList', store)
}

View File

@ -0,0 +1,57 @@
<template>
<a-card :bordered="false">
<a-tabs :default-active-key="activeTab">
<a-tab-pane key="1" tab="我的收藏">
<a-card title="我的收藏题目(共5题)" :bordered="false" :bodyStyle="{padding: '0px !important'}" :headStyle="{paddingLeft: '0px !important'}">
<template v-for="(item, index) in 10" >
<div :key="index">
<DbQuestionInfoItem :questionIndex="index+1" ></DbQuestionInfoItem>
<a-divider></a-divider>
</div>
</template>
</a-card>
</a-tab-pane>
<a-tab-pane key="2" tab="错题集">
<a-card title="我的错题题目(共5题)" :bordered="false" :bodyStyle="{padding: '0px !important'}" :headStyle="{paddingLeft: '0px !important'}">
<template v-for="(item, index) in 10" >
<div :key="index">
<DbQuestionInfoItem :questionIndex="index+1" ></DbQuestionInfoItem>
<a-divider></a-divider>
</div>
</template>
</a-card>
</a-tab-pane>
<a-tab-pane key="3" tab="答题记录">
<a-card v-for="(item, index) in 10" :key="index" style="margin-bottom: 15px;">
<div class="flex-center" >
<div style="flex: 1;">
<h3>建筑施工安全培训第一期课程学习6.8-7.8</h3>
<div><span style="margin-right: 20px;">答题情况做对10/30</span><span>交卷时间2021-06-18 12:00</span></div>
</div>
<div style="flex: 0 0 200px; text-align: right;">
<div :span="24" style="margin-bottom: 10px;"><a-button type="primary" size="small" >查看报告</a-button></div>
<div :span="24"><a-button type="primary" size="small">查看报告</a-button></div>
</div>
</div>
</a-card>
</a-tab-pane>
</a-tabs>
</a-card>
</template>
<script>
import DbQuestionInfoItem from '@/components/DbQuestionInfoItem/index.vue'
export default {
components: { DbQuestionInfoItem },
data () {
return {
activeTab: '1'
}
}
}
</script>
<style>
</style>

View File

@ -0,0 +1,109 @@
<template>
<div class="CourseCatalogue-box">
<ul class="list-box">
<li class="list-item" v-for="(item, index) in 3" :key="index">
<div class="list-item-title"><span style="margin-right: 10px;">第一章</span>建筑施工安全培训第一期课程学习</div>
<ul class="sub-list">
<li @click="handlerItem(j, item)" class="sub-list-item" v-for="(j, k) in 4" :key="`${index}-${k}`">
<div class="sub-item-info">
<VideoOne theme="filled" fill="#ccc" style="margin-right: 6px;" size="1.2em"></VideoOne>1.1
建筑施工安全培训第一期课程学习
</div>
<div v-if="`${index}-${k}` === selectedId" class="sub-item-status">
正在学习...<History
theme="filled"
tyle="margin-left: 10px;"
size="1.2em"
style="margin-left: 10px;"
></History>
</div>
<div v-else class="sub-item-status">
<Round theme="filled" strokeWidth="6" fill="#666" style="margin-left: 10px;"></Round>
</div>
</li>
</ul>
</li>
</ul>
</div>
</template>
<script>
import { VideoOne, Round, History } from '@icon-park/vue'
export default {
components: { VideoOne, Round, History },
data () {
return {
selectedId: '1-1'
}
},
methods: {
handlerItem (item, pItem) {
this.$emit('changeVideo', { item, pItem })
}
}
}
</script>
<style lang="less" scoped>
.learn-detail {
display: flex;
}
.learn-detail-video {
flex: 1;
}
.learn-detail-list {
flex: 220px;
}
.list-box,
.sub-list {
margin: 0;
padding: 0;
}
.list-item-title {
color: 16px;
font-weight: bold;
color: #333;
padding: 10px 0;
}
.sub-list-item {
color: #666;
padding-bottom: 10px;
&:hover {
color: #1890ff;
}
}
.sub-list {
padding-left: 20px;
}
.sub-list-item {
display: flex;
align-items: center;
justify-content: space-between;
cursor: pointer;
.sub-item-info {
flex: 1;
display: flex;
}
.sub-item-status {
flex: 0 0 200px;
font-size: 12px;
text-align: right;
color: #1890ff;
display: flex;
align-items: center;
justify-content: flex-end;
}
}
.list-item {
width: 100%;
}
</style>

View File

@ -0,0 +1,40 @@
<template>
<a-modal title="课中检查" :visible="visible" :confirm-loading="confirmLoading" :footer="null" :closable="false">
<DbQuestionItem></DbQuestionItem>
<div class="text-center margin-top">
<a-button type="primary" @click="handlerSubmit">提交</a-button>
</div>
<p class="tip-info margin-top">
注意每段课程学习完成后都会随机出现1道小题答对题目方可继续下一部分学习您有2次机会否则之前上一小段学习时间不计算学时需要重新学习
</p>
</a-modal>
</template>
<script>
import DbQuestionItem from '@/components/DbQuestionItem/index.vue'
export default {
components: { DbQuestionItem },
data () {
return {
visible: false,
confirmLoading: false
}
},
methods: {
show(){
this.visible = true
},
handlerSubmit () {
//
this.visible = false
}
}
}
</script>
<style lang="less" scoped>
.tip-info {
margin-top: 10px;
color: #f5222d;
}
</style>

View File

@ -0,0 +1,37 @@
<template>
<div>
<a-table :columns="columns" :data-source="data">
<template slot="date" slot-scope="text, record, index">
全天<a-button style="margin-left: 6px;" type="primary" size="small">进入考试</a-button>
</template>
</a-table>
</div>
</template>
<script>
export default {
data() {
return {
columns: [
{ dataIndex: 'courseName', title: '课程' },
{ dataIndex: 'type', title: '考核方式' },
{ dataIndex: 'examType', title: '考试方式' },
{ dataIndex: 'subType', title: '提交形式' },
{ dataIndex: 'date', title: '考试时间段', scopedSlots: { customRender: 'date' } },
{ dataIndex: 'time', title: '考试时长' }
],
data: [
{
courseName: '1.1,建筑施工安全培训第一期课程学习',
type: '机考',
examType: '闭卷',
subType: '网络提交',
time: '150分钟'
}
]
}
}
}
</script>
<style></style>

View File

@ -0,0 +1,113 @@
<template>
<a-card :bordered="false">
<div class="video-box">
<div class="video-title">建筑施工安全培训第一期课程学习</div>
<div class="video-main">
<video-player
class="vjs-custom-skin"
ref="videoPlayer"
:options="playerOptions"
:playsinline="true"
@ended="onPlayerEnded($event)"
></video-player>
</div>
</div>
<div class="video-info">
<a-tabs :default-active-key="activeTab" @change="tabChange">
<a-tab-pane key="1" tab="课程目录">
<div class="tab-box">
<CourseCatalogue></CourseCatalogue>
</div>
</a-tab-pane>
<a-tab-pane key="2" tab="模拟测试">
<div class="tab-box">
<SimulationTest></SimulationTest>
</div>
</a-tab-pane>
<a-tab-pane key="3" tab="作业"> Content of Tab Pane 3 </a-tab-pane>
<a-tab-pane key="4" tab="学习统计"> Content of Tab Pane 3 </a-tab-pane>
</a-tabs>
</div>
<!-- 课中考试 -->
<ExamDialog ref="examDialog"></ExamDialog>
</a-card>
</template>
<script>
import 'video.js/dist/video-js.css'
import 'vue-video-player/src/custom-theme.css'
import { videoPlayer } from 'vue-video-player'
import CourseCatalogue from './CourseCatalogue.vue'
import SimulationTest from './SimulationTest.vue'
import ExamDialog from './ExamDialog.vue'
export default {
components: { CourseCatalogue, SimulationTest, ExamDialog, videoPlayer },
data() {
return {
activeTab: '1',
playerOptions: {
height: '360',
autoplay: false,
muted: false,
language: 'zh-CN',
sources: [
{
type: 'video/mp4',
src: 'http://vjs.zencdn.net/v/oceans.mp4',
},
],
controlBar: {
/* 使用children的形式可以控制每一个控件的位置以及显示与否 */
children: [
{ name: 'playToggle' }, //
{ name: 'currentTimeDisplay' }, //
{ name: 'progressControl' }, //
// { name: 'durationDisplay' }, //
{
name: 'volumePanel', //
inline: false, // 使
},
{ name: 'FullscreenToggle' }, //
],
},
poster: 'https://surmon-china.github.io/vue-quill-editor/static/images/surmon-1.jpg',
},
}
},
methods: {
tabChange(key) {
console.log('key', key)
// this.$refs.videoPlayer.player.play() //
// this.$refs.videoPlayer.player.pause() //
// this.$refs.videoPlayer.player.src('src') //
},
//
onPlayerEnded() {
this.$refs.examDialog.show()
},
},
}
</script>
<style lang="less" scoped>
.video-title {
font-size: 20px;
font-weight: bold;
margin-bottom: 15px;
color: #333;
}
.video-info {
margin-top: 15px;
}
::v-deep .ant-tabs-nav-scroll {
text-align: center;
}
.tab-box {
max-width: 800px;
width: 100%;
margin: 0 auto;
}
</style>

View File

@ -0,0 +1,139 @@
<template>
<div class="exam-detail">
<div class="answer-card">
<a-card :bordered="false">
<div class="answer-card-title"><a-icon type="arrow-left" style="margin-right: 6px;" />答题卡</div>
<div class="answer-cart-time">
倒计时:
<b style="margin-left: 5px;"><a-statistic-countdown :value="deadline" :valueStyle="{ fontSize: '16px' }" @finish="onFinish"/></b>
</div>
<DbAnswerCard :pref="$refs"></DbAnswerCard>
<div class="answer-cart-footer flex-center">
<a-button type="primary" size="large">交卷</a-button>
</div>
</a-card>
</div>
<div class="exam-line"></div>
<div class="exam-box">
<a-card :bordered="false" ref="question">
<div class="exam-title">建筑施工安全培训第一期课程学习(模拟考试)</div>
<div class="exam-main">
<template>
<div class="sub-title">单选题共30题每题1.5共45分</div>
<DbQuestionItem
:id="`type1-${index}`"
:index="index + 1"
:type="1"
v-for="(item, index) in 5"
:key="`type1-${index}`"
></DbQuestionItem>
</template>
<template>
<div class="sub-title">多选题共10题每题1.5共15分</div>
<DbQuestionItem
:id="`type2-${index}`"
:index="index + 1"
:type="2"
v-for="(item, index) in 5"
:key="`type2-${index}`"
></DbQuestionItem>
</template>
<template>
<div class="sub-title">判断题共10题每题1.5共15分</div>
<DbQuestionItem
:id="`type3-${index}`"
:index="index + 1"
:type="3"
v-for="(item, index) in 5"
:key="`type3-${index}`"
></DbQuestionItem>
</template>
<template>
<div class="sub-title">填空题共10题每题1.5共15分</div>
<DbQuestionItem :index="index + 1" :type="4" v-for="(item, index) in 5" :key="`type4-${index}`"></DbQuestionItem>
</template>
<template>
<div class="sub-title">简答题共10题每题1.5共15分</div>
<DbQuestionItem :index="index + 1" :type="5" v-for="(item, index) in 5" :key="`type5-${index}`"></DbQuestionItem>
</template>
</div>
</a-card>
</div>
</div>
</template>
<script>
import DbQuestionItem from '@/components/DbQuestionItem/index'
import DbAnswerCard from '@/components/DbAnswerCard/index'
export default {
components: {
DbQuestionItem,
DbAnswerCard
},
data() {
return {
deadline: Date.now() + 1000 * 60 * 60 * 1.5
}
},
methods: {
//
onFinish() {}
}
}
</script>
<style lang="less" scoped>
.exam-detail {
display: flex;
max-height: 100%;
.exam-box {
flex: 1;
}
.exam-line {
flex: 0 0 10px;
}
.answer-card {
flex: 0 0 400px;
}
}
.exam-title {
font-size: 20px;
font-weight: bold;
padding: 10px 0;
border-bottom: 1px solid #c3c3c3;
text-align: center;
}
.exam-main {
padding-right: 50px;
}
.sub-title {
font-size: 16px;
font-weight: bold;
color: #333;
margin-top: 10px;
}
.answer-card-title {
font-size: 16px;
font-weight: bold;
display: flex;
align-items: center;
// justify-content: space-between;
border-bottom: 1px solid #c3c3c3;
padding-bottom: 10px;
}
.answer-cart-time {
font-size: 14px;
color: #333;
padding: 10px 0;
text-align: right;
display: flex;
align-items: center;
justify-content: flex-end;
}
</style>

View File

@ -0,0 +1,13 @@
<template>
</template>
<script>
export default {
}
</script>
<style>
</style>

View File

@ -0,0 +1,126 @@
<template>
<a-card
:bordered="false"
:loading="loading"
>
<a-table
ref="table"
:pageSize="5"
:columns="columns"
:showPagination="false"
:data-source="dataList"
:rowKey="record => record.id">
<span slot="action" slot-scope="text, record, index">
<a v-if="index % 3 == 1" @click="$refs.userForm.edit(record)">添加课程</a>
<a v-if="index % 3 == 2" @click="$refs.userForm.edit(record)">继续学习</a>
<a v-if="index % 3 == 0">已完成学习</a>
</span>
</a-table>
<CentralizedTrainingDetail ref="centralizedTrainingDetail"></CentralizedTrainingDetail>
</a-card>
</template>
<script>
import { userPage, userDel, passwordReset } from '@/api/security/user'
import { getCourseList, deleteCourse } from '@/api/course/course'
import { dictionaryDropDown } from '@/api/sys/dictionaryItem'
import { dictToTree } from '@/utils/util'
import CentralizedTrainingDetail from './CentralizedTrainingDetail.vue'
export default {
components: {
CentralizedTrainingDetail
},
data () {
return {
dataList: [],
activeTab: '1',
loading: true,
columns: [
{
title: '培训名称',
dataIndex: 'courseName',
scopedSlots: { customRender: 'courseName' }
},
{
title: '培训时间',
dataIndex: 'courseTypeName'
},
{
title: '培训地点',
dataIndex: 'date'
},
{
title: '培训状态',
dataIndex: 'status'
},
{
title: '操作',
width: '150px',
dataIndex: 'action',
scopedSlots: { customRender: 'action' }
}
],
// Promise
loadData: parameter => {
return getCourseList(Object.assign(parameter, this.queryParam)).then(res => {
return res
})
},
selectedRows: [], //
options: {}
}
},
created () {
this.dictionaryDropDown()
},
methods: {
tabChange (key) {
console.log('key', key)
},
//
handlerDetail () {
this.$refs.aycourseDetail.visible = true
},
//
dictionaryDropDown () {
dictionaryDropDown({ dictionaryCode: '0006' }).then((res) => {
this.loading = false
this.queryOptions[1].options = dictToTree(res.data, [], 0)
})
},
classificationChange (value) {
this.queryParam.classification = value
},
//
handleRefresh () {
},
sysUserDelete (param) {
userDel(param)
.then(res => {
if (res.code === 200) {
this.$message.success('删除成功')
this.$refs.table.refresh()
} else {
this.$message.error('删除失败:' + res.msg)
}
})
.catch(err => {
this.$message.error('删除错误:' + err.msg)
})
},
handleOk () {
this.$refs.table.refresh()
}
}
}
</script>
<style lang="less" scoped>
.table-operator {
margin-bottom: 18px;
}
button {
margin-right: 8px;
}
</style>

View File

@ -0,0 +1,59 @@
<template>
<a-modal title="集中培训详情" :width="800" :visible="visible" :confirmLoading="confirmLoading" :footer="null">
<a-descriptions title="User Info">
<a-descriptions-item label="UserName">
Zhou Maomao
</a-descriptions-item>
<a-descriptions-item label="Telephone">
1810000000
</a-descriptions-item>
<a-descriptions-item label="Live">
Hangzhou, Zhejiang
</a-descriptions-item>
<a-descriptions-item label="Remark">
empty
</a-descriptions-item>
<a-descriptions-item label="Address">
No. 18, Wantang Road, Xihu District, Hangzhou, Zhejiang, China
</a-descriptions-item>
</a-descriptions>
</a-modal>
</template>
<script>
export default {
data () {
return {
visible: false,
confirmLoading: false
}
},
methods: {
//
handlerStartLearn () {}
}
}
</script>
<style lang="less" scoped>
.cover-img {
width: 100%;
height: 200px;
border: 1px solid #e8e8e8;
border-radius: 10px;
overflow: hidden;
img {
width: 100%;
height: 100%;
}
}
.info-text {
font-size: 16px;
color: #666;
line-height: 1.8;
h2 {
line-height: 1.2;
}
}
</style>

View File

@ -0,0 +1,140 @@
<template>
<a-card
:bordered="false"
:loading="loading"
>
<a-row :gutter="16">
<a-col
:span="6"
:md="4"
:sm="6"
v-for="(item, index) in 8"
:key="index">
<a-card hoverable style="width: 100%; margin-bottom: 15px;">
<img
slot="cover"
alt="example"
src="https://gw.alipayobjects.com/zos/rmsportal/JiqGstEfoWAOHiTxclqi.png"
/>
<div>
<h4>建筑安全施工生产注意事项</h4>
<div class="flex-center justify-between">
<div>课时: 24小时</div>
<div>选修课</div>
</div>
</div>
</a-card>
</a-col>
</a-row>
</a-card>
</template>
<script>
import { userPage, userDel, passwordReset } from '@/api/security/user'
import { getCourseList, deleteCourse } from '@/api/course/course'
import { dictionaryDropDown } from '@/api/sys/dictionaryItem'
import { dictToTree } from '@/utils/util'
import { STable, SearchCom } from '@/components'
export default {
components: {
STable,
SearchCom
},
data () {
return {
dataList: [],
activeTab: '1',
loading: true,
queryParam: {
classification: '' //
},
queryOptions: [
{ type: 'input', placeholder: '课程名称', key: 'courseName' },
{ type: 'select-dic-tree', placeholder: '请选择课程类别', key: 'courseType', options: [] }
],
//
columns: [
{
title: '课程名称',
dataIndex: 'courseName',
scopedSlots: { customRender: 'courseName' }
},
{
title: '课程类别',
dataIndex: 'courseTypeName'
},
{
title: '学习时间',
dataIndex: 'date'
},
{
title: '操作',
width: '150px',
dataIndex: 'action',
scopedSlots: { customRender: 'action' }
}
],
// Promise
loadData: parameter => {
return getCourseList(Object.assign(parameter, this.queryParam)).then(res => {
return res
})
},
selectedRows: [], //
options: {}
}
},
created () {
this.dictionaryDropDown()
},
methods: {
tabChange (key) {
console.log('key', key)
},
//
handlerDetail () {
this.$refs.aycourseDetail.visible = true
},
//
dictionaryDropDown () {
dictionaryDropDown({ dictionaryCode: '0006' }).then((res) => {
this.queryOptions[1].options = dictToTree(res.data, [], 0)
this.loading = false
})
},
classificationChange (value) {
this.queryParam.classification = value
},
//
handleRefresh () {
},
sysUserDelete (param) {
userDel(param)
.then(res => {
if (res.code === 200) {
this.$message.success('删除成功')
this.$refs.table.refresh()
} else {
this.$message.error('删除失败:' + res.msg)
}
})
.catch(err => {
this.$message.error('删除错误:' + err.msg)
})
},
handleOk () {
this.$refs.table.refresh()
}
}
}
</script>
<style lang="less" scoped>
.table-operator {
margin-bottom: 18px;
}
button {
margin-right: 8px;
}
</style>

View File

@ -0,0 +1,194 @@
<template>
<a-card :bordered="false" :loading="loading">
<div class="table-page-search-wrapper">
<SearchCom
:form="queryParam"
:list="queryOptions"
@search="handleRefresh"
@reset="
() => {
queryParam = {}
handleRefresh()
}
"></SearchCom>
</div>
</br>
<s-table
ref="table"
:pageSize="5"
:columns="columns"
:data="loadData"
:alert="options.alert"
:rowKey="record => record.id">
<span slot="index" slot-scope="text, record, index">
{{ index + 1 }}
</span>
<template slot="courseName" slot-scope="text, record, index">
<a-button @click="handlerDetail(record)" type="link" >{{ record.courseName }}</a-button>
</template>
<span slot="status" slot-scope="text, record">
<a-tag color="red">未开始</a-tag>
</span>
<template slot="progress" slot-scope="text, record">
<a-progress :percent="30" />
</template>
<span slot="action" slot-scope="text, record, index">
<a v-if="index % 3 == 1" @click="$refs.userForm.edit(record)">添加课程</a>
<a v-if="index % 3 == 2" @click="$refs.userForm.edit(record)">继续学习</a>
<a v-if="index % 3 == 0">已完成学习</a>
<!-- <a-divider type="vertical" />
<a-dropdown v-if="hasPerm('sys:user:resetPwd') || hasPerm('sys:user:grantRole') || hasPerm('sys:user:del')">
<a class="ant-dropdown-link"> 更多 <a-icon type="down" /> </a>
<a-menu slot="overlay">
<a-menu-item v-if="hasPerm('sys:user:resetPwd')">
<a-popconfirm placement="topRight" title="确认重置密码?" @confirm="() => resetPwd(record)">
<a>重置密码</a>
</a-popconfirm>
</a-menu-item>
<a-menu-item v-if="hasPerm('sys:user:grantRole')">
<a @click="$refs.userRoleForm.userRole(record)">授权角色</a>
</a-menu-item>
<a-menu-item v-if="hasPerm('sys:user:delete')">
<a-popconfirm placement="topRight" title="确认删除?" @confirm="() => singleDelete(record)">
<a>删除</a>
</a-popconfirm>
</a-menu-item>
</a-menu>
</a-dropdown> -->
</span>
</s-table>
<MycourseDetail ref="aycourseDetail"></MycourseDetail>
</a-card>
</template>
<script>
import { userPage, userDel, passwordReset } from '@/api/security/user'
import { getCourseList, deleteCourse } from '@/api/course/course'
import { dictionaryDropDown } from '@/api/sys/dictionaryItem'
import { dictToTree } from '@/utils/util'
import { STable, SearchCom } from '@/components'
import MycourseDetail from './MycourseDetail.vue'
export default {
components: {
STable,
SearchCom,
MycourseDetail
// UserForm,
// UserRoleForm
},
data () {
return {
loading: true,
queryParam: {
classification: '' //
},
queryOptions: [
{ type: 'input', placeholder: '课程名称', key: 'courseName' },
{ type: 'select-dic-tree', placeholder: '课程类别', key: 'courseType', options: [] }
],
//
columns: [
{
title: '序号',
width: '80px',
scopedSlots: { customRender: 'index' },
align: 'center'
},
{
title: '课程名称',
dataIndex: 'courseName',
scopedSlots: { customRender: 'courseName' }
},
{
title: '课程类别',
dataIndex: 'courseTypeName'
},
{
title: '学习时间',
dataIndex: 'date'
},
{
title: '课程状态',
dataIndex: 'status',
scopedSlots: { customRender: 'status' },
width: '120px'
},
{
title: '课程进度',
dataIndex: 'progress',
scopedSlots: { customRender: 'progress' },
width: '180px'
},
{
title: '已休学时',
dataIndex: 'yxxs',
scopedSlots: { customRender: 'present' }
}
],
// Promise
loadData: parameter => {
return getCourseList(Object.assign(parameter, this.queryParam)).then(res => {
return res
})
},
selectedRows: [], //
options: {}
}
},
created () {
this.dictionaryDropDown()
this.columns.push({
title: '操作',
width: '150px',
dataIndex: 'action',
scopedSlots: { customRender: 'action' }
})
},
methods: {
//
handlerDetail () {
this.$refs.aycourseDetail.visible = true
},
//
dictionaryDropDown () {
dictionaryDropDown({ dictionaryCode: '0006' }).then((res) => {
this.queryOptions[1].options = dictToTree(res.data, [], 0)
this.loading = false
})
},
classificationChange (value) {
this.queryParam.classification = value
},
//
handleRefresh () {
},
sysUserDelete (param) {
userDel(param)
.then(res => {
if (res.code === 200) {
this.$message.success('删除成功')
this.$refs.table.refresh()
} else {
this.$message.error('删除失败:' + res.msg)
}
})
.catch(err => {
this.$message.error('删除错误:' + err.msg)
})
},
handleOk () {
this.$refs.table.refresh()
}
}
}
</script>
<style lang="less" scoped>
.table-operator {
margin-bottom: 18px;
}
button {
margin-right: 8px;
}
</style>

View File

@ -0,0 +1,71 @@
<template>
<a-modal title="课程详情" :width="800" :visible="visible" :confirmLoading="confirmLoading" :footer="null">
<div class="course-main">
<a-row>
<a-col :span="8">
<div class="cover-img">
<img class src="../../../../src/assets/img/demo1.jpeg" alt="" />
</div>
</a-col>
<a-col class="info-text" :span="16" style="padding-left: 20px;">
<h2>建筑施工安全培训第一期课程学习</h2>
<div>
<span style="margin-right: 20px;">课程类型: 必修课</span>
<span>主讲老师: 陈国栋</span>
</div>
<div>开课周期 2020-05-08 ~ 2022-05-31</div>
<div>共10课时每节课60分钟</div>
<a-button @click="handlerStartLearn" style="margin-top: 15px;" type="primary">开始学习</a-button>
</a-col>
</a-row>
<a-row>
<h3 class="modal-title">课程介绍</h3>
<h4>建筑施工安全培训第一期课程学习</h4>
<div>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean euismod bibendum laoreet. Proin gravida dolor
sit amet lacus accumsan et viverra justo commodo. Proin sodales pulvinar sic tempor. Sociis natoque penatibus
et magnis dis parturient montes, nascetur ridiculus mus. Nam fermentum, nulla luctus pharetra vulputate, felis
tellus mollis orci, sed rhoncus pronin sapien nunc accuan eget.
</div>
</a-row>
</div>
</a-modal>
</template>
<script>
export default {
data() {
return {
visible: false,
confirmLoading: false
}
},
methods: {
//
handlerStartLearn () {}
}
}
</script>
<style lang="less" scoped>
.cover-img {
width: 100%;
height: 200px;
border: 1px solid #e8e8e8;
border-radius: 10px;
overflow: hidden;
img {
width: 100%;
height: 100%;
}
}
.info-text {
font-size: 16px;
color: #666;
line-height: 1.8;
h2 {
line-height: 1.2;
}
}
</style>

View File

@ -0,0 +1,149 @@
<template>
<a-card
:bordered="false"
:loading="loading"
>
<a-tabs :default-active-key="activeTab" @change="tabChange">
<a-tab-pane key="1" tab="年度培训计划">
<a-table
ref="table"
:pageSize="5"
:columns="columns"
:showPagination="false"
:data-source="dataList"
:rowKey="record => record.id">
<span slot="action" slot-scope="text, record, index">
<a v-if="index % 3 == 1" @click="$refs.userForm.edit(record)">添加课程</a>
<a v-if="index % 3 == 2" @click="$refs.userForm.edit(record)">继续学习</a>
<a v-if="index % 3 == 0">已完成学习</a>
</span>
</a-table>
</a-tab-pane>
<a-tab-pane key="2" tab="单位培训计划">
<a-table
ref="table"
:pageSize="5"
:columns="columns"
:showPagination="false"
:data-source="dataList"
:rowKey="record => record.id">
<span slot="action" slot-scope="text, record, index">
<a v-if="index % 3 == 1" @click="$refs.userForm.edit(record)">添加课程</a>
<a v-if="index % 3 == 2" @click="$refs.userForm.edit(record)">继续学习</a>
<a v-if="index % 3 == 0">已完成学习</a>
</span>
</a-table>
</a-tab-pane>
</a-tabs>
</a-card>
</template>
<script>
import { userPage, userDel, passwordReset } from '@/api/security/user'
import { getCourseList, deleteCourse } from '@/api/course/course'
import { dictionaryDropDown } from '@/api/sys/dictionaryItem'
import { dictToTree } from '@/utils/util'
import { STable, SearchCom } from '@/components'
export default {
components: {
STable,
SearchCom
},
data () {
return {
dataList: [],
activeTab: '1',
loading: true,
queryParam: {
classification: '' //
},
queryOptions: [
{ type: 'input', placeholder: '课程名称', key: 'courseName' },
{ type: 'select-dic-tree', placeholder: '请选择课程类别', key: 'courseType', options: [] }
],
//
columns: [
{
title: '课程名称',
dataIndex: 'courseName',
scopedSlots: { customRender: 'courseName' }
},
{
title: '课程类别',
dataIndex: 'courseTypeName'
},
{
title: '学习时间',
dataIndex: 'date'
},
{
title: '操作',
width: '150px',
dataIndex: 'action',
scopedSlots: { customRender: 'action' }
}
],
// Promise
loadData: parameter => {
return getCourseList(Object.assign(parameter, this.queryParam)).then(res => {
return res
})
},
selectedRows: [], //
options: {}
}
},
created () {
this.dictionaryDropDown()
},
methods: {
tabChange (key) {
console.log('key', key)
},
//
handlerDetail () {
this.$refs.aycourseDetail.visible = true
},
//
dictionaryDropDown () {
dictionaryDropDown({ dictionaryCode: '0006' }).then((res) => {
this.queryOptions[1].options = dictToTree(res.data, [], 0)
this.loading = false
})
},
classificationChange (value) {
this.queryParam.classification = value
},
//
handleRefresh () {
},
sysUserDelete (param) {
userDel(param)
.then(res => {
if (res.code === 200) {
this.$message.success('删除成功')
this.$refs.table.refresh()
} else {
this.$message.error('删除失败:' + res.msg)
}
})
.catch(err => {
this.$message.error('删除错误:' + err.msg)
})
},
handleOk () {
this.$refs.table.refresh()
}
}
}
</script>
<style lang="less" scoped>
.table-operator {
margin-bottom: 18px;
}
button {
margin-right: 8px;
}
</style>

View File

@ -0,0 +1,49 @@
<template>
<div>
<a-card :bordered="false" >
<a-card title="我的课程" :bodyStyle="{padding: '0px !important'}" >
<MyCourseList></MyCourseList>
</a-card>
<br />
<a-card title="培训计划" :bodyStyle="{padding: '0px !important'}">
<a slot="extra" href="#">查看更多</a>
<TrainingPlan></TrainingPlan>
</a-card>
<br />
<a-card title="集中培训" :bodyStyle="{padding: '0px !important'}">
<a slot="extra" href="#">查看更多</a>
<CentralizedTraining></CentralizedTraining>
</a-card>
<br />
<a-card title="系统推荐课程" :bodyStyle="{padding: '0px !important'}">
<a slot="extra" href="#">查看更多</a>
<CourseRecommendation></CourseRecommendation>
</a-card>
</a-card>
</div>
</template>
<script>
import MyCourseList from './MyCourseList.vue' //
import TrainingPlan from './TrainingPlan.vue' //
import CentralizedTraining from './CentralizedTraining.vue' //
import CourseRecommendation from './CourseRecommendation.vue' //
export default {
components: {
MyCourseList,
TrainingPlan,
CentralizedTraining,
CourseRecommendation
},
data () {
return {
}
},
methods: {
}
}
</script>
<style lang="less">
</style>

View File

@ -0,0 +1,190 @@
<template>
<div>
<a-card :bordered="false">
<div class="table-page-search-wrapper">
<SearchCom
:form="queryParam"
:list="queryOptions"
@search="handleRefresh"
@reset="
() => {
queryParam = {}
handleRefresh()
}
"></SearchCom>
</a-form>
</div>
<s-table
ref="table"
:columns="columns"
:data="loadData"
:alert="options.alert"
:rowKey="record => record.id"
>
<span slot="index" slot-scope="text, record, index">
{{ index + 1 }}
</span>
<span slot="status" slot-scope="text, record">
<a-tag color="red">未开始</a-tag>
</span>
<template slot="progress" slot-scope="text, record">
<a-progress :percent="30" />
</template>
<span slot="action" slot-scope="text, record, index">
<a v-if="index%3 == 1" @click="$refs.userForm.edit(record)">添加课程</a>
<a v-if="index%3 == 2" @click="$refs.userForm.edit(record)">继续学习</a>
<a v-if="index%3 == 0">已完成学习</a>
<!-- <a-divider type="vertical" />
<a-dropdown v-if="hasPerm('sys:user:resetPwd') || hasPerm('sys:user:grantRole') || hasPerm('sys:user:del')">
<a class="ant-dropdown-link"> 更多 <a-icon type="down" /> </a>
<a-menu slot="overlay">
<a-menu-item v-if="hasPerm('sys:user:resetPwd')">
<a-popconfirm placement="topRight" title="确认重置密码?" @confirm="() => resetPwd(record)">
<a>重置密码</a>
</a-popconfirm>
</a-menu-item>
<a-menu-item v-if="hasPerm('sys:user:grantRole')">
<a @click="$refs.userRoleForm.userRole(record)">授权角色</a>
</a-menu-item>
<a-menu-item v-if="hasPerm('sys:user:delete')">
<a-popconfirm placement="topRight" title="确认删除?" @confirm="() => singleDelete(record)">
<a>删除</a>
</a-popconfirm>
</a-menu-item>
</a-menu>
</a-dropdown> -->
</span>
</s-table>
<!-- <user-form ref="userForm" @ok="handleOk" /> -->
<!-- <user-role-form ref="userRoleForm" @ok="handleOk" /> -->
</a-card>
</div>
</template>
<script>
import { STable, SearchCom } from '@/components'
import { userPage, userDel, passwordReset } from '@/api/security/user'
export default {
components: {
STable,
SearchCom
},
data () {
return {
//
queryParam: {},
queryOptions: [
{ type: 'input', placeholder: '课程名称', key: 'courseName' },
{ type: 'select', placeholder: '课程分类', key: 'courseType', options: [{ name: '年度培训计划', id: 1 }, { name: '单位培训计划', id: 2 }] },
{ type: 'select', placeholder: '课程状态', key: 'courseStatus', options: [{ name: '在修', id: 1 }] }
],
//
columns: [
{
title: '序号',
width: '80px',
scopedSlots: { customRender: 'index' },
align: 'center'
},
{
title: '课程名称',
dataIndex: 'courseName'
},
{
title: '课程类别',
dataIndex: 'type'
},
{
title: '学习时间',
dataIndex: 'date'
},
{
title: '课程状态',
dataIndex: 'status',
scopedSlots: { customRender: 'status' },
width: '120px'
},
{
title: '课程进度',
dataIndex: 'progress',
scopedSlots: { customRender: 'progress' },
width: '180px'
},
{
title: '已休学时',
dataIndex: 'yxxs',
scopedSlots: { customRender: 'present' }
},
{
title: '操作',
width: '150px',
dataIndex: 'action',
scopedSlots: { customRender: 'action' }
}
],
// Promise
loadData: parameter => {
return userPage(Object.assign(parameter, this.queryParam)).then(res => {
return res
})
},
selectedRows: [], //
options: {
}
}
},
created () {
},
methods: {
handleRefresh () {
},
//
resetPwd (record) {
passwordReset({ id: record.id }).then(res => {
if (res.code === 200) {
this.$message.success('重置成功')
// this.$refs.table.refresh()
} else {
this.$message.error('重置失败:' + res.msg)
}
})
},
//
singleDelete (record) {
const param = { ids: record.id }
this.sysUserDelete(param)
},
//
batchDelete () {
const paramIds = this.selectedRowKeys.join(',')
const param = { ids: paramIds }
this.sysUserDelete(param)
},
sysUserDelete (param) {
userDel(param)
.then(res => {
if (res.code === 200) {
this.$message.success('删除成功')
this.$refs.table.refresh()
} else {
this.$message.error('删除失败:' + res.msg)
}
})
.catch(err => {
this.$message.error('删除错误:' + err.msg)
})
},
handleOk () {
this.$refs.table.refresh()
}
}
}
</script>
<style lang="less">
.table-operator {
margin-bottom: 18px;
}
button {
margin-right: 8px;
}
</style>

View File

@ -0,0 +1,92 @@
<template>
<a-card :bordered="false" :loading="loading">
<div class="table-page-search-wrapper">
<div class="flex-center justify-between">
<div style="flex: 1;">
<SearchCom
:form="queryParam"
:list="queryOptions"
@search="handleRefresh"
@reset="
() => {
queryParam = {}
handleRefresh()
}
"></SearchCom>
</div>
<div class="flex-center" style="flex: 0 0 300px;">
<a-button type="link">我的收藏</a-button>
<a-button type="link">错题集</a-button>
<a-button type="link">答题记录</a-button>
</div>
</div>
</div>
</br>
<a-card v-for="(item, index) in 6" :key="index" :bordered="false" :bodyStyle="{paddingLeft: '0px !important'}" :headStyle="{paddingLeft: '0px !important'}" >
<template slot="title">
<b>安全生产法律法规</b><span class="sub-txt">共999题</span>
</template>
<a-row :gutter="16">
<a-col
:span="6"
:lg="4"
:md="6"
:sm="8"
:xs="12"
v-for="(item, index) in 8"
:key="index">
<a-card hoverable style="width: 100%; margin-bottom: 15px;">
<div class="flex-center"><h4>建筑工程相关安全生产法律</h4></div>
<div class="flex-center" style="margin-top: 10px;">
<a-button type="primary" size="small" round>开始答题</a-button>
</div>
</a-card>
</a-col>
</a-row>
</a-card>
</a-card>
</template>
<script>
import { SearchCom } from '@/components'
import { dictionaryDropDown } from '@/api/sys/dictionaryItem'
import { dictToTree } from '@/utils/util'
export default {
components: { SearchCom },
data () {
return {
loading: true,
queryParam: {
classification: '' //
},
queryOptions: [
{ type: 'select-dic-tree', placeholder: '课程分类', key: 'courseType', options: [] }
]
}
},
mounted(){
this.dictionaryDropDown()
},
methods: {
handleRefresh () {
},
dictionaryDropDown () {
dictionaryDropDown({ dictionaryCode: '0009' }).then((res) => {
const result = dictToTree(res.data, [], 0)
this.queryOptions[0].options = result
this.loading = false
})
}
}
}
</script>
<style lang="less" scoped>
.sub-txt{
color: #666;
font-size: 12px;
margin-left: 10px;
}
</style>

View File

@ -203,8 +203,8 @@ export default {
if (res.code == 200) { if (res.code == 200) {
this.form.resetFields(`pid`, []) this.form.resetFields(`pid`, [])
this.menuTreeData = [{ this.menuTreeData = [{
'id': '-1', 'id': '0',
'parentId': '0', 'parentId': '-1',
'name': '顶级', 'name': '顶级',
'value': '0', 'value': '0',
'pid': '0', 'pid': '0',

19476
yarn.lock

File diff suppressed because it is too large Load Diff