717 lines
19 KiB
Vue
717 lines
19 KiB
Vue
<template>
|
|
<div class="app-container">
|
|
|
|
<el-form
|
|
ref="postForm"
|
|
:model="postForm"
|
|
:rules="rules"
|
|
label-width="121px"
|
|
class="form-container"
|
|
>
|
|
<el-tabs v-model="activeName">
|
|
<el-tab-pane label="基本信息" name="first">
|
|
<el-form-item :label="$t('main.shop')" prop="key" v-if="userLevel === 1">
|
|
<el-select
|
|
v-model="postForm.shop"
|
|
:placeholder="'选择'+$t('main.shop')"
|
|
name="shop"
|
|
required
|
|
class="w100"
|
|
>
|
|
<el-option
|
|
v-for="item in allDepts"
|
|
:key="item._id"
|
|
:label="item.name"
|
|
:value="item._id"
|
|
/>
|
|
</el-select>
|
|
</el-form-item>
|
|
<el-form-item
|
|
style="margin-bottom: 40px;"
|
|
label="活动名称:"
|
|
prop="name"
|
|
>
|
|
<el-input
|
|
v-model="postForm.name"
|
|
placeholder="输入活动名称"
|
|
name="name"
|
|
required
|
|
/>
|
|
</el-form-item>
|
|
<el-form-item
|
|
label="激活:"
|
|
prop="active"
|
|
>
|
|
<el-switch
|
|
v-model="postForm.active"
|
|
name="active"
|
|
active-color="#13ce66"
|
|
inactive-color="#ff4949"
|
|
required
|
|
/>
|
|
</el-form-item>
|
|
<el-form-item
|
|
prop="desc"
|
|
label="简介:"
|
|
style="margin-bottom: 30px;"
|
|
>
|
|
<el-input type="textarea" v-model="postForm.desc"></el-input>
|
|
</el-form-item>
|
|
<el-form-item
|
|
prop="icon"
|
|
label="活动icon"
|
|
>
|
|
<upload-corp-image
|
|
field="image-file"
|
|
@crop-upload-success="iconUploadSuccess"
|
|
:width="400"
|
|
:height="120"
|
|
img-format="png"
|
|
v-model="postForm.icon"
|
|
>
|
|
|
|
</upload-corp-image>
|
|
</el-form-item>
|
|
|
|
<el-form-item
|
|
prop="banner"
|
|
label="活动配图"
|
|
>
|
|
<upload-corp-image
|
|
field="image-file"
|
|
@crop-upload-success="bannerUploadSuccess"
|
|
:width="400"
|
|
:height="260"
|
|
img-format="png"
|
|
v-model="postForm.banner"
|
|
>
|
|
|
|
</upload-corp-image>
|
|
</el-form-item>
|
|
<el-form-item
|
|
label="开始/结束日期"
|
|
prop="dataRange"
|
|
>
|
|
<el-date-picker
|
|
v-model="dataRange"
|
|
type="daterange"
|
|
align="right"
|
|
style="width: 40%"
|
|
unlink-panels
|
|
range-separator="至"
|
|
start-placeholder="开始日期"
|
|
end-placeholder="结束日期"
|
|
>
|
|
</el-date-picker>
|
|
</el-form-item>
|
|
</el-tab-pane>
|
|
<el-tab-pane label="题库设置" name="second">
|
|
<el-form-item
|
|
label="题目数量:"
|
|
prop="qcount"
|
|
>
|
|
<el-input
|
|
v-model="postForm.qcount"
|
|
placeholder="本次活动题目数量"
|
|
name="qcount"
|
|
type="number"
|
|
required
|
|
/>
|
|
</el-form-item>
|
|
<el-form-item
|
|
label="每题答题时间:"
|
|
prop="timeone"
|
|
>
|
|
<el-input
|
|
v-model="postForm.timeone"
|
|
placeholder="每一题的答题时间(单位: 秒)"
|
|
name="timeone"
|
|
type="number"
|
|
required
|
|
/>
|
|
</el-form-item>
|
|
<el-form-item
|
|
label="题目来源:"
|
|
prop="source"
|
|
>
|
|
<el-select
|
|
v-model="postForm.source"
|
|
placeholder="选择题目来源"
|
|
name="source"
|
|
required
|
|
>
|
|
<el-option :value="0" label="系统题库">系统题库</el-option>
|
|
<el-option :value="1" label="自定义题库">自定义题库</el-option>
|
|
<el-option :value="2" :label="$t('main.shop') + '题库'">{{$t('main.shop')}}题库</el-option>
|
|
</el-select>
|
|
</el-form-item>
|
|
<el-form-item :label="$t('main.shop') + '分类'" v-show="postForm.source === 2" prop="shopCates">
|
|
<el-select
|
|
v-model="postForm.shopCates"
|
|
placeholder="选择"
|
|
name="typeSelect"
|
|
required
|
|
class="w100"
|
|
multiple
|
|
>
|
|
<el-option
|
|
v-for="item in shopCates"
|
|
:key="item"
|
|
:label="item"
|
|
:value="item"
|
|
/>
|
|
</el-select>
|
|
</el-form-item>
|
|
<el-form-item
|
|
label="题库分类"
|
|
v-show="postForm.source === 0"
|
|
>
|
|
<el-tree
|
|
:data="typeOptions"
|
|
show-checkbox
|
|
accordion
|
|
node-key="id"
|
|
ref="typeTree"
|
|
highlight-current
|
|
:default-checked-keys="typeSelected"
|
|
:props="defaultProps">
|
|
</el-tree>
|
|
|
|
</el-form-item>
|
|
<el-form-item
|
|
label="题目"
|
|
v-show="postForm.source === 1"
|
|
>
|
|
<puzzle-list
|
|
v-model= "postForm.questions"
|
|
:examid="postForm._id"
|
|
></puzzle-list>
|
|
</el-form-item>
|
|
|
|
</el-tab-pane>
|
|
<el-tab-pane label="奖励设置" name="third">
|
|
<div class="action-bar">
|
|
<el-button
|
|
type="primary"
|
|
icon="el-icon-edit"
|
|
@click="handleCreateReward"
|
|
>
|
|
添加
|
|
</el-button>
|
|
</div>
|
|
<el-table
|
|
:data="postForm.rewardInfo"
|
|
border
|
|
fit
|
|
highlight-current-row
|
|
>
|
|
<el-table-column
|
|
label="分数"
|
|
prop="rank"
|
|
>
|
|
</el-table-column>
|
|
<el-table-column
|
|
label="奖励"
|
|
prop="coupon"
|
|
:formatter = "formatCoupon"
|
|
>
|
|
</el-table-column>
|
|
<el-table-column
|
|
align="center"
|
|
width="180"
|
|
label="操作"
|
|
fixed="right"
|
|
>
|
|
<template slot-scope="scope">
|
|
<el-button
|
|
type="primary"
|
|
size="small"
|
|
icon="el-icon-edit"
|
|
@click="handleEdit(scope)"
|
|
>
|
|
编辑
|
|
</el-button>
|
|
<el-button
|
|
type="danger"
|
|
size="small"
|
|
style="margin-left: 10px"
|
|
@click="deleteRank(scope)"
|
|
>
|
|
{{ $t('permission.delete') }}
|
|
</el-button>
|
|
</template>
|
|
</el-table-column>
|
|
</el-table>
|
|
</el-tab-pane>
|
|
</el-tabs>
|
|
<el-form-item>
|
|
<el-button
|
|
type="primary"
|
|
@click="submitForm"
|
|
>
|
|
保存
|
|
</el-button>
|
|
<el-button @click="onCancel">
|
|
取消
|
|
</el-button>
|
|
</el-form-item>
|
|
</el-form>
|
|
|
|
<el-dialog
|
|
:visible.sync="dialogVisible"
|
|
title="编辑奖励"
|
|
>
|
|
<el-form
|
|
:model="record"
|
|
ref="modalForm"
|
|
:rules="modalRules"
|
|
label-width="80px"
|
|
label-position="left"
|
|
>
|
|
<el-form-item label="分数" prop="rank">
|
|
<el-input
|
|
v-model="record.rank"
|
|
placeholder="分数"
|
|
type="number"
|
|
style="width: 30%"
|
|
/>
|
|
</el-form-item>
|
|
|
|
<el-form-item label="奖励" prop="coupon">
|
|
<el-select
|
|
v-model="record.coupon"
|
|
placeholder="选择奖励"
|
|
name="coupon"
|
|
required
|
|
class="w100"
|
|
>
|
|
<el-option
|
|
v-for="item in coupons"
|
|
:key="item._id"
|
|
:label="item.name"
|
|
:value="item._id"
|
|
/>
|
|
</el-select>
|
|
</el-form-item>
|
|
<el-form-item label="数量" prop="count">
|
|
<el-input
|
|
v-model="record.count"
|
|
placeholder="数量"
|
|
type="number"
|
|
/>
|
|
</el-form-item>
|
|
<el-form-item>
|
|
<el-button
|
|
type="primary"
|
|
@click="saveReward"
|
|
v-permission="['shopexam:edit']"
|
|
>
|
|
保存
|
|
</el-button>
|
|
<el-button @click="closeModal">
|
|
取消
|
|
</el-button>
|
|
</el-form-item>
|
|
</el-form>
|
|
</el-dialog>
|
|
</div>
|
|
</template>
|
|
|
|
<script lang="ts">
|
|
import { Component, Vue, Watch } from 'vue-property-decorator'
|
|
import { AppModule } from '@/store/modules/app'
|
|
import { ITagView, TagsViewModule } from '@/store/modules/tags-view'
|
|
import MaterialInput from '@/components/MaterialInput/index.vue'
|
|
import Sticky from '@/components/Sticky/index.vue'
|
|
import UploadImage from '@/components/UploadImage/index.vue'
|
|
import RegionPicker from '@/components/RegionPicker/index.vue'
|
|
import { getMyShop, getShops } from '@/api/shop'
|
|
|
|
import { defaultExamData, getExam, saveExam } from '@/api/exam'
|
|
import { getAllCategory } from '@/api/question'
|
|
import { cloneDeep } from 'lodash'
|
|
import { getCoupons, ICouponData } from '@/api/coupon'
|
|
import { IShopData } from '@/api/types'
|
|
import { ElTree } from 'element-ui/types/tree'
|
|
import { UserModule } from '@/store/modules/user'
|
|
import { defaultRewardData, IRewardData } from '@/api/activity'
|
|
import PuzzleList from './components/PuzzleList.vue'
|
|
import UploadCorpImage from '@/components/UploadCorpImage/index.vue'
|
|
import { EVENT_COUPON_UPDATE, EVENT_EXAM_UPDATE, EVENT_SHOP_UPDATE, EventBus } from '@/utils/event-bus'
|
|
import { getShopCategory } from '@/api/shoppuzzle'
|
|
|
|
@Component({
|
|
name: 'ExamEditor',
|
|
components: {
|
|
MaterialInput,
|
|
Sticky,
|
|
UploadImage,
|
|
RegionPicker,
|
|
PuzzleList,
|
|
UploadCorpImage
|
|
}
|
|
})
|
|
export default class extends Vue {
|
|
private validateRequire = (rule: any, value: string, callback: Function) => {
|
|
if (value === '') {
|
|
if (rule.field === 'imageURL') {
|
|
this.$message({
|
|
message: 'Upload cover image is required',
|
|
type: 'error'
|
|
})
|
|
} else {
|
|
this.$message({
|
|
message: rule.field + ' 是必填的',
|
|
type: 'error'
|
|
})
|
|
}
|
|
callback(new Error(rule.field + ' 是必填的'))
|
|
} else {
|
|
callback()
|
|
}
|
|
}
|
|
|
|
private data = {}
|
|
private activeName = 'first'
|
|
|
|
private dataRange: Date[] = []
|
|
private shopCates: string[] = []
|
|
|
|
private postForm = Object.assign({}, defaultExamData)
|
|
private loading = false
|
|
private allDepts: IShopData[] = []
|
|
private typeOptions: {id: string, label: string, children?: any[]}[] = []
|
|
private typeSelected: string[] = []
|
|
private defaultProps = {
|
|
children: 'children',
|
|
label: 'label'
|
|
}
|
|
|
|
private rules = {
|
|
name: [{ validator: this.validateRequire }]
|
|
}
|
|
|
|
private tempTagView?: ITagView
|
|
|
|
private dialogType = 'new'
|
|
private record: IRewardData = {}
|
|
private dialogVisible = false
|
|
private modalRules = {
|
|
rank: [{ required: true, message: '请输入分数', trigger: 'blur' }
|
|
]
|
|
}
|
|
|
|
private coupons: ICouponData[] = []
|
|
|
|
private params: any = { }
|
|
|
|
$refs!: {
|
|
modalForm: HTMLFormElement
|
|
postForm: HTMLFormElement
|
|
typeTree: ElTree<any, any>
|
|
}
|
|
|
|
get userLevel() {
|
|
return UserModule.level
|
|
}
|
|
|
|
get lang() {
|
|
return AppModule.language
|
|
}
|
|
|
|
async created() {
|
|
const id = this.$route.params?.id
|
|
await this.getRemoteCategory()
|
|
if (id) {
|
|
await this.fetchData(id)
|
|
}
|
|
if (UserModule.level === 1) {
|
|
await this.getRemoteDeptList()
|
|
EventBus.$on(EVENT_SHOP_UPDATE, () => {
|
|
this.getRemoteDeptList()
|
|
})
|
|
} else {
|
|
this.postForm.shop = UserModule.department
|
|
await this.fetchMyShop()
|
|
await this.getRemoteShopCategory()
|
|
}
|
|
|
|
this.tempTagView = Object.assign({}, this.$route)
|
|
EventBus.$on(EVENT_COUPON_UPDATE, () => {
|
|
if (this.postForm.shop) {
|
|
this.getCouponList(this.postForm.shop)
|
|
}
|
|
})
|
|
}
|
|
|
|
beforeDestory() {
|
|
EventBus.$off(EVENT_COUPON_UPDATE)
|
|
if (UserModule.level === 1) {
|
|
EventBus.$off(EVENT_SHOP_UPDATE)
|
|
}
|
|
}
|
|
|
|
private async fetchData(id: string) {
|
|
try {
|
|
const { data } = await getExam(id, { /* Your params here */ })
|
|
console.log(data)
|
|
this.postForm = data
|
|
if (data.beginTime !== undefined && data.endTime !== undefined) {
|
|
this.dataRange.push(new Date(data.beginTime))
|
|
this.dataRange.push(new Date(data.endTime))
|
|
}
|
|
// Just for test
|
|
const title = this.lang === 'zh' ? '编辑挑战' : 'Edit Exam'
|
|
// Set tagsview title
|
|
this.setTagsViewTitle(title)
|
|
// Set page title
|
|
this.setPageTitle(title)
|
|
// this.$forceUpdate()
|
|
} catch (err) {
|
|
console.error(err)
|
|
}
|
|
}
|
|
|
|
private setTagsViewTitle(title: string) {
|
|
const tagView = this.tempTagView
|
|
if (tagView) {
|
|
tagView.title = `${title}-${this.postForm._id}`
|
|
TagsViewModule.updateVisitedView(tagView)
|
|
}
|
|
}
|
|
|
|
private setPageTitle(title: string) {
|
|
document.title = `${title} - ${this.postForm._id}`
|
|
}
|
|
|
|
private async submitForm() {
|
|
try {
|
|
await this.$refs.postForm.validate()
|
|
if (this.dataRange.length > 1) {
|
|
this.postForm.beginTime = this.dataRange[0].getTime()
|
|
this.postForm.endTime = this.dataRange[1].getTime()
|
|
}
|
|
if (this.postForm.source === 0 && this.$refs.typeTree) {
|
|
this.postForm.qtypes = this.$refs.typeTree.getCheckedKeys()
|
|
} else {
|
|
this.postForm.qtypes = []
|
|
}
|
|
this.loading = true
|
|
const { data } = await saveExam(this.postForm)
|
|
this.postForm = data
|
|
this.loading = false
|
|
this.$notify({
|
|
title: 'Success',
|
|
message: 'The post save successfully',
|
|
type: 'success',
|
|
duration: 2000
|
|
})
|
|
EventBus.$emit(EVENT_EXAM_UPDATE, {})
|
|
} catch (err) {
|
|
console.error('Submit Error!')
|
|
return false
|
|
}
|
|
}
|
|
|
|
private async onCancel() {
|
|
try {
|
|
await this.$confirm('确认不保存当前挑战信息?', 'Warning', {
|
|
confirmButtonText: '确定',
|
|
cancelButtonText: '取消',
|
|
type: 'warning'
|
|
})
|
|
this.$store.dispatch('delView', this.$route)
|
|
this.$router.go(-1)
|
|
} catch (e) {
|
|
|
|
}
|
|
}
|
|
|
|
private async getRemoteDeptList() {
|
|
const { data } = await getShops({})
|
|
if (!data.records) return
|
|
this.allDepts = data.records
|
|
}
|
|
|
|
private async fetchMyShop() {
|
|
const { data } = await getMyShop()
|
|
this.typeSelected = data.qtypes
|
|
console.log(this.typeSelected)
|
|
this.$refs.typeTree.setCheckedKeys(this.typeSelected)
|
|
}
|
|
|
|
@Watch('postForm.shop')
|
|
private onShopChange() {
|
|
if (this.postForm.shop) {
|
|
this.getCouponList(this.postForm.shop)
|
|
this.getRemoteShopCategory()
|
|
}
|
|
|
|
if (this.postForm.qtypes?.length > 0) {
|
|
this.typeSelected = this.postForm.qtypes
|
|
} else if (this.postForm.shop) {
|
|
let currentShop
|
|
for (const p of this.allDepts) {
|
|
if (p._id === this.postForm.shop) {
|
|
currentShop = p
|
|
break
|
|
}
|
|
}
|
|
if (currentShop) {
|
|
this.typeSelected = currentShop.qtypes
|
|
} else {
|
|
this.typeSelected = []
|
|
}
|
|
}
|
|
this.$refs.typeTree.setCheckedKeys(this.typeSelected)
|
|
}
|
|
|
|
// begin of set puzzle types
|
|
private async getRemoteCategory() {
|
|
const { data } = await getAllCategory()
|
|
for (const cat of data) {
|
|
const subArr = []
|
|
for (const s of cat.children) {
|
|
subArr.push({
|
|
id: s._id,
|
|
label: s.name
|
|
})
|
|
}
|
|
this.typeOptions.push({
|
|
id: cat._id,
|
|
label: cat.name,
|
|
children: subArr
|
|
})
|
|
}
|
|
this.typeOptions.push({
|
|
id: 'customer',
|
|
label: '自定义',
|
|
children: []
|
|
})
|
|
}
|
|
|
|
// begin of award list
|
|
private async getCouponList(shop: string) {
|
|
const { data } = await getCoupons({ shop })
|
|
this.coupons = data.records
|
|
}
|
|
|
|
private formatCoupon(row: number, column: number, cellValue: string, index: number) {
|
|
let result = `未知(${cellValue})`
|
|
const data = this.postForm.rewardInfo[index]
|
|
for (const dep of this.coupons) {
|
|
if (dep._id === cellValue) {
|
|
result = dep.name
|
|
break
|
|
}
|
|
}
|
|
return `${result} x ${data.count}`
|
|
}
|
|
|
|
private formatRank(row: number, column: number, cellValue: string, index: number) {
|
|
const data = this.postForm.rewardInfo[index]
|
|
let result = `第 ${data.rank} 名`
|
|
if (data.rankEnd) {
|
|
result = `第 ${data.rank} 至 ${data.rankEnd} 名`
|
|
}
|
|
return result
|
|
}
|
|
|
|
private async deleteRank(scope: any) {
|
|
const { $index } = scope
|
|
try {
|
|
await this.$confirm('Confirm to remove the record?', 'Warning', {
|
|
confirmButtonText: 'Confirm',
|
|
cancelButtonText: 'Cancel',
|
|
type: 'warning'
|
|
})
|
|
this.postForm.rewardInfo.splice($index, 1)
|
|
this.$message({
|
|
type: 'success',
|
|
message: '删除成功, 请点击保存'
|
|
})
|
|
} catch (err) {
|
|
|
|
}
|
|
}
|
|
|
|
private handleCreateReward() {
|
|
this.record = Object.assign({}, defaultRewardData)
|
|
this.record.id = this.postForm.rewardInfo.length
|
|
this.dialogType = 'new'
|
|
this.dialogVisible = true
|
|
}
|
|
|
|
private handleEdit(scope: any) {
|
|
this.dialogType = 'edit'
|
|
this.dialogVisible = true
|
|
this.record = cloneDeep(scope.row)
|
|
}
|
|
|
|
private closeModal() {
|
|
this.dialogVisible = false
|
|
this.$refs.modalForm.clearValidate()
|
|
}
|
|
|
|
private saveReward() {
|
|
const isEdit = this.dialogType === 'edit';
|
|
(this.$refs.modalForm as HTMLFormElement).validate(async(valid: boolean) => {
|
|
if (!valid) {
|
|
this.$message.error('请按要求填写表单')
|
|
return false
|
|
}
|
|
if (isEdit) {
|
|
for (let index = 0; index < this.postForm.rewardInfo.length; index++) {
|
|
if (this.postForm.rewardInfo[index].id === this.record.id) {
|
|
this.postForm.rewardInfo.splice(index, 1, Object.assign({}, this.record))
|
|
break
|
|
}
|
|
}
|
|
} else {
|
|
this.postForm.rewardInfo.push(this.record)
|
|
}
|
|
this.dialogVisible = false
|
|
this.$notify({
|
|
title: 'Success',
|
|
dangerouslyUseHTMLString: true,
|
|
message: `
|
|
奖励成功保存, 请点击保存
|
|
`,
|
|
type: 'success'
|
|
})
|
|
})
|
|
}
|
|
|
|
private iconUploadSuccess(imgUrl: string) {
|
|
console.log('upload icon success: ' + imgUrl)
|
|
this.postForm.icon = imgUrl
|
|
this.$forceUpdate()
|
|
}
|
|
|
|
private bannerUploadSuccess(imgUrl: string) {
|
|
console.log('upload banner success: ' + imgUrl)
|
|
this.postForm.banner = imgUrl
|
|
this.$forceUpdate()
|
|
}
|
|
|
|
private async getRemoteShopCategory() {
|
|
try {
|
|
const { data } = await getShopCategory(this.postForm.shop)
|
|
this.shopCates = data
|
|
this.$forceUpdate()
|
|
} catch (err) {
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
.action-bar{
|
|
margin-bottom: 15px;
|
|
}
|
|
.excel-upload-input {
|
|
display: none;
|
|
z-index: -9999;
|
|
}
|
|
</style>
|