feat: ui开发

This commit is contained in:
cgd_mac 2022-01-07 14:43:46 +08:00
parent 1a372f89d4
commit c08648778b
26 changed files with 11269 additions and 49050 deletions

View File

@ -1,5 +1,24 @@
{
"printWidth": 120,
"tabWidth": 2,
"singleQuote": true,
"trailingComma": "none",
"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": {
"@ant-design-vue/pro-layout": "^0.3.4",
"@antv/data-set": "^0.10.2",
"@icon-park/vue": "^1.3.5",
"ant-design-vue": "^1.7.7",
"axios": "^0.19.0",
"core-js": "^3.1.2",
"dplayer": "^1.26.0",
"draftjs-to-html": "^0.9.1",
"enquire.js": "^2.1.6",
"file-saver": "^2.0.5",

View File

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

View File

@ -1,7 +1,7 @@
<template>
<a-config-provider :locale="locale">
<div id="app">
<router-view/>
<router-view />
</div>
</a-config-provider>
</template>
@ -11,17 +11,50 @@ import { domTitle, setDocumentTitle } from '@/utils/domUtil'
import { i18nRender } from '@/locales'
export default {
data () {
return {
}
data() {
return {}
},
computed: {
locale () {
locale() {
//
const { title } = this.$route.meta
title && (setDocumentTitle(`${i18nRender(title)} - ${domTitle}`))
title && setDocumentTitle(`${i18nRender(title)} - ${domTitle}`)
return this.$i18n.getLocaleMessage(this.$store.getters.lang).antLocale
}
}
}
</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;
}
.flex-center{
display: flex;
align-items: center;
justify-content: center;
}
.nowrap{
white-space: nowrap;
}
</style>

View File

@ -7,29 +7,28 @@ const dictionaryApi = {
page: '/sys/dictionary/pageList'
}
export function dictionaryAdd (params) {
export function dictionaryAdd(params) {
return request({
url: dictionaryApi.add,
method: 'post',
data: params
})
}
export function dictionaryUpdate (params) {
export function dictionaryUpdate(params) {
return request({
url: dictionaryApi.update,
method: 'post',
data: params
})
}
export function dictionaryDel (params) {
export function dictionaryDel(params) {
return request({
url: dictionaryApi.del,
method: 'post',
params: params
})
}
export function dictionaryPage (params) {
console.log(params)
export function dictionaryPage(params) {
return request({
url: dictionaryApi.page,
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,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: '',
id: 'ueditor' + Math.random(),
editorConfig: {
lang: 'zh-cn',
UEDITOR_HOME_URL: '/static/plugins/ueditor/',
serverUrl: '/dawa/sys/ueditor/config',
},
@ -43,6 +44,7 @@
immediate: true,
handler: function (config) {
const defaults = {
lang: 'zh-cn',
UEDITOR_HOME_URL: '/static/plugins/ueditor/',
serverUrl: '/dawa/sys/ueditor/config',
}

View File

@ -107,3 +107,16 @@ ol {
text-align: left;
}
}
// 公用样式
.text-center {
text-align: center;
}
.text-right {
text-align: right;
}
.margin-top {
margin-top: 15px;
}

View File

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

View File

@ -3,7 +3,7 @@ import moment from 'moment'
import 'moment/locale/zh-cn'
moment.locale('zh-cn')
Vue.filter('NumberFormat', function (value) {
Vue.filter('NumberFormat', function(value) {
if (!value) {
return '0'
}
@ -11,7 +11,31 @@ Vue.filter('NumberFormat', function (value) {
return intPartFormat
})
Vue.filter('AmountFormat', function (val) {
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) {
if (!val) {
return '0.00'
}
@ -32,7 +56,7 @@ Vue.filter('AmountFormat', function (val) {
return (sign ? '-' : '') + val + '.' + cents
})
Vue.filter('dayjs', function (dataStr, pattern = 'YYYY-MM-DD HH:mm:ss') {
Vue.filter('dayjs', function(dataStr, pattern = 'YYYY-MM-DD HH:mm:ss') {
return moment(dataStr).format(pattern)
})

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,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>
<div>123</div>
</template>
<script>
export default {
}
</script>
<style>
</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,151 @@
<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"
:showHeader="false"
: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"
:showHeader="false"
: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,43 @@
<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>
</a-card>
<br />
<a-card title="系统推荐课程" :bodyStyle="{padding: '0px !important'}">
<a slot="extra" href="#">查看更多</a>
</a-card>
</a-card>
</div>
</template>
<script>
import MyCourseList from './MyCourseList.vue'
import TrainingPlan from './TrainingPlan.vue'
export default {
components: {
MyCourseList,
TrainingPlan
},
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>

19476
yarn.lock

File diff suppressed because it is too large Load Diff