medal management

This commit is contained in:
xiaomlove
2022-01-19 23:54:55 +08:00
parent 3fa8fd19c0
commit 64a1f2bb0c
39 changed files with 1282 additions and 171 deletions

View File

@@ -38,6 +38,9 @@
<el-menu-item-group>
<el-menu-item index="/exam-user"><i class="el-icon-menu" />Exam user</el-menu-item>
</el-menu-item-group>
<el-menu-item-group>
<el-menu-item index="/medal"><i class="el-icon-menu" />Medal</el-menu-item>
</el-menu-item-group>
<el-menu-item-group>
<el-menu-item index="/setting"><i class="el-icon-menu" />Setting</el-menu-item>
</el-menu-item-group>

View File

@@ -54,6 +54,16 @@ const router = createRouter({
name: 'agent-allow-form',
component: () => import('../views/agent-allow/form.vue')
},
{
path: '/medal',
name: 'medal',
component: () => import('../views/medal/index.vue')
},
{
path: '/medal-form',
name: 'medal-form',
component: () => import('../views/medal/form.vue')
},
{
path: '/setting',
name: 'setting',

View File

@@ -72,6 +72,24 @@ const api = {
deleteExam: (id) => {
return axios.delete('exams/' + id);
},
listMedal: (params = {}) => {
return axios.get('medals', {params: params});
},
storeMedal: (params = {}) => {
return axios.post('medals', params);
},
updateMedal: (id, params = {}) => {
return axios.put('medals/' + id, params);
},
getMedal: (id) => {
return axios.get('medals/' + id);
},
deleteMedal: (id) => {
return axios.delete('medals/' + id);
},
listClass: (params = {}) => {
return axios.get('user-classes', {params: params});
},
@@ -107,7 +125,10 @@ const api = {
},
listSystemInfo: () => {
return axios.get('dashboard/system-info')
}
},
removeUserMedal: (id) => {
return axios.delete('user-medals/' + id);
},
}

View File

@@ -47,4 +47,6 @@ export const pathMap = {
'exam-form': 'Exam form',
'exam-user': 'Exam user',
'setting': "Setting",
'medal': 'Medal',
'medal-form': 'Medal form',
}

View File

@@ -0,0 +1,162 @@
<template>
<div>
<el-row>
<el-col :span="12">
<el-form :model="formData" :rules="rules" ref="formRef" label-width="200px" class="formData">
<el-form-item label="Name" prop="name">
<el-input v-model="formData.name" placeholder=""></el-input>
</el-form-item>
<el-form-item label="Price" prop="price">
<el-input v-model="formData.price" placeholder="Seed bonus"></el-input>
</el-form-item>
<el-form-item label="Get type" prop="get_type">
<el-radio-group v-model="formData.get_type">
<el-radio :label="1">Exchange</el-radio>
<el-radio :label="2">Grant</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="Image large" prop="image_large">
<el-input v-model="formData.image_large" placeholder=""></el-input>
</el-form-item>
<el-form-item label="Image small" prop="image_small">
<el-input v-model="formData.image_small" placeholder=""></el-input>
</el-form-item>
<el-form-item label="Duration" prop="duration">
<el-input v-model="formData.duration" placeholder="Unit: day, if empty, it's valid forever"></el-input>
</el-form-item>
<el-form-item label="Description" prop="description">
<el-input type="textarea" v-model="formData.description" placeholder=""></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitAdd()">Submit</el-button>
</el-form-item>
</el-form>
</el-col>
</el-row>
</div>
</template>
<script>
import { reactive, ref, toRefs, onMounted, onBeforeUnmount, getCurrentInstance } from 'vue'
import { ElMessage } from 'element-plus'
import { useRoute, useRouter } from 'vue-router'
import { localGet } from '../../utils'
import api from "../../utils/api";
export default {
name: 'MedalForm',
setup() {
const { proxy } = getCurrentInstance()
console.log('proxy', proxy)
const formRef = ref(null)
const route = useRoute()
const router = useRouter()
const { id } = route.query
const state = reactive({
token: localGet('token') || '',
id: id,
allClasses: [],
formData: {
name: '',
description: '',
image_large: '',
image_small: '',
duration: '',
price: '',
get_type: ''
},
rules: {
name: [
{ required: 'true', }
],
price: [
{ required: 'true', }
],
image_large: [
{ required: 'true', }
],
image_small: [
{ required: 'true', }
],
description: [
{ required: 'true', }
],
get_type: [
{required: 'true'}
]
},
})
onMounted( async () => {
if (id) {
api.getMedal(id).then(res => {
state.formData.name = res.data.name
state.formData.image_large = res.data.image_large
state.formData.image_small = res.data.image_small
state.formData.description = res.data.description
state.formData.price = res.data.price
state.formData.duration = res.data.duration
state.formData.get_type = res.data.get_type
})
}
})
onBeforeUnmount(() => {
})
const submitAdd = () => {
formRef.value.validate(async (vaild) => {
if (vaild) {
let params = state.formData;
console.log(params)
if (id) {
await api.updateMedal(id, params)
} else {
await api.storeMedal(params)
}
await router.push({name: 'medal'})
}
})
}
const handleBeforeUpload = (file) => {
const sufix = file.name.split('.')[1] || ''
if (!['jpg', 'jpeg', 'png'].includes(sufix)) {
ElMessage.error('请上传 jpg、jpeg、png 格式的图片')
return false
}
}
const handleUrlSuccess = (val) => {
state.formData.goodsCoverImg = val.data || ''
}
const handleChangeCate = (val) => {
state.categoryId = val[2] || 0
}
const listAllClass = async () => {
let res = await api.listClass()
state.allClasses = res.data
}
const listAllIndex = async () => {
let res = await api.listMedalIndex()
state.formData.indexes = res.data
}
const getMedal = async (id) => {
let res = await api.getMedal(id)
console.log(res)
}
return {
...toRefs(state),
formRef,
submitAdd,
handleBeforeUpload,
handleUrlSuccess,
handleChangeCate,
}
}
}
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,151 @@
<template>
<el-card class="">
<template #header>
<div class="nexus-table-header">
<div class="left">
</div>
<div class="right">
<el-button type="primary" size="small" icon="el-icon-plus" @click="handleAdd">Add</el-button>
</div>
</div>
</template>
<el-table
v-loading="loading"
ref="multipleTable"
:data="tableData"
tooltip-effect="dark"
@selection-change="handleSelectionChange">
<el-table-column
type="selection"
width="55">
</el-table-column>
<el-table-column
prop="id"
label="Id"
width="50"
>
</el-table-column>
<el-table-column
prop="name"
label="Name"
></el-table-column>
<el-table-column
prop="image_large"
label="Large image"
></el-table-column>
<el-table-column
prop="image_small"
label="Small image"
></el-table-column>
<el-table-column
prop="get_type_text"
label="Get type"
></el-table-column>
<el-table-column
prop="price"
label="Price(bonus)"
></el-table-column>
<el-table-column
prop="duration"
label="Duration(day)"
></el-table-column>
<el-table-column
label="Action"
width="100"
>
<template #default="scope">
<a style="cursor: pointer; margin-right: 10px" @click="handleEdit(scope.row.id)">Edit</a>
<el-popconfirm
title="Confirm Delete ?"
@confirm="handleDelete(scope.row.id)"
>
<template #reference>
<a style="cursor: pointer">Delete</a>
</template>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
<!--总数超过一页再展示分页器-->
<el-pagination
background
layout="prev, pager, next"
:total="total"
:page-size="perPage"
:current-page="currentPage"
@current-change="changePage"
/>
</el-card>
</template>
<script>
import { onMounted, reactive, ref, toRefs } from 'vue'
import { ElMessage } from 'element-plus'
import { useRouter } from 'vue-router'
import api from '../../utils/api'
import { useTable, renderTableData } from '../../utils/table'
export default {
name: 'MedalTable',
setup() {
const multipleTable = ref(null)
const router = useRouter()
const state = useTable()
onMounted(() => {
console.log('MedalTable onMounted')
fetchTableData()
})
const fetchTableData = async () => {
state.loading = true
let res = await api.listMedal(state.query)
renderTableData(res, state)
state.loading = false
}
const handleAdd = () => {
router.push({ name: 'medal-form' })
}
const handleEdit = (id) => {
router.push({ path: '/medal-form', query: { id } })
}
const handleDelete = async (id) => {
let res = await api.deleteMedal(id)
ElMessage.success(res.msg)
state.query.page = 1;
await fetchTableData()
}
const handleSelectionChange = (val) => {
state.multipleSelection = val
}
const changePage = (val) => {
state.query.page = val
fetchTableData()
}
return {
...toRefs(state),
multipleTable,
handleSelectionChange,
handleAdd,
handleEdit,
handleDelete,
fetchTableData,
changePage,
}
}
}
</script>
<style scoped>
.swiper-container {
min-height: 100%;
}
.el-card.is-always-shadow {
min-height: 100%!important;
}
</style>

View File

@@ -153,12 +153,62 @@
</el-col>
</el-row>
</el-card>
<el-row v-if="baseInfo.valid_medals && baseInfo.valid_medals.length">
<el-col :span="12">
<el-card >
<template #header>
<div class="card-header">
<span>Medal</span>
</div>
</template>
<el-table
v-loading="loading"
ref="multipleTable"
:data="baseInfo.valid_medals"
tooltip-effect="dark"
>
<el-table-column
prop="name"
label="Name"
></el-table-column>
<el-table-column
prop="image_large"
label="Image"
>
</el-table-column>
<el-table-column
prop="expire_at"
label="Expire at"
></el-table-column>
<el-table-column
label="Action"
width="100"
>
<template #default="scope">
<el-popconfirm
title="Confirm Remove ?"
@confirm="handleRemoveUserMedal(scope.row.user_medal_id)"
>
<template #reference>
<a style="cursor: pointer">Remove</a>
</template>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
</el-card>
</el-col>
</el-row>
</div>
<DialogAssignExam ref="assignExam" :reload="fetchPageData"/>
<DialogViewInviteInfo ref="viewInviteInfo" />
<DialogDisableUser ref="disableUser" :reload="fetchPageData" />
<DialogModComment ref="modComment" />
<DialogModComment ref="modComment" />
<DialogResetPassword ref="resetPassword" />
</template>
@@ -240,6 +290,12 @@ export default {
const handleResetPassword = async () => {
resetPassword.value.open(id)
}
const handleRemoveUserMedal = async (id) => {
let res = await api.removeUserMedal(id)
ElMessage.success(res.msg)
await fetchPageData()
}
return {
...toRefs(state),
handleRemoveExam,
@@ -252,6 +308,7 @@ export default {
handleGetModComment,
handleResetPassword,
fetchPageData,
handleRemoveUserMedal,
assignExam,
viewInviteInfo,
disableUser,
@@ -271,10 +328,10 @@ export default {
text-align: left;
tr {
th {
padding-bottom: 10px;
padding-bottom: 4px;
}
td {
padding: 10px 0;
padding: 4px 0;
}
}
}