提交 d850c524 authored 作者: 王鹏飞's avatar 王鹏飞

feat: 旅程模板

上级 e68cd7e5
......@@ -14,6 +14,7 @@
"axios": "^1.3.1",
"blueimp-md5": "^2.19.0",
"element-plus": "^2.2.28",
"lodash-es": "^4.17.21",
"pinia": "^2.0.30",
"vue": "^3.2.47",
"vue-router": "^4.1.6"
......
......@@ -21,6 +21,7 @@
"axios": "^1.3.1",
"blueimp-md5": "^2.19.0",
"element-plus": "^2.2.28",
"lodash-es": "^4.17.21",
"pinia": "^2.0.30",
"vue": "^3.2.47",
"vue-router": "^4.1.6"
......
......@@ -148,9 +148,9 @@ defineExpose({ refetch, tableRef })
@change="search"
v-if="item.type === 'select'">
<el-option
:label="option[item.labelKey] || option.label"
:value="option[item.valueKey] || option.value"
v-for="(option, index) in item.options"
:label="option[item.labelKey] || option.label || option"
:value="option[item.valueKey] || option.value || option"
:key="index" />
</el-select>
</template>
......
import httpRequest from '@/utils/axios'
import type { TripTemplateListRequest, TripTemplateCreateRequest, TripTemplateUpdateRequest } from './types'
// 获取旅程模板列表
export function getTripTemplateList(params: TripTemplateListRequest) {
return httpRequest.get('/api/lab/v1/experiment/itinerary/list', { params })
}
// 创建旅程模板
export function createTripTemplateList(data: TripTemplateCreateRequest) {
return httpRequest.post('/api/lab/v1/experiment/itinerary/create', data)
}
// 更新旅程模板
export function updateTripTemplateList(data: TripTemplateUpdateRequest) {
return httpRequest.post('/api/lab/v1/experiment/itinerary/update', data)
}
<script setup lang="ts">
import type { TripTemplate } from '../types'
import type { FormInstance, FormRules } from 'element-plus'
import { ElMessage } from 'element-plus'
import { createTripTemplateList, updateTripTemplateList } from '../api'
import { tripTemplateTypeList } from '@/utils/dictionary'
import { pick } from 'lodash-es'
const props = defineProps<{ data?: TripTemplate }>()
const emit = defineEmits<{
(e: 'update'): void
(e: 'update:modelValue', visible: boolean): void
}>()
const isUpdate = $computed(() => !!props.data?.id)
const title = $computed(() => (isUpdate ? '修改旅程模板' : '新建旅程模板'))
const formRef = $ref<FormInstance>()
const form = reactive({
id: '',
name: '',
type: '1',
score: 100,
is_view_answer: '1',
status: '1'
})
watchEffect(() => {
if (props.data) Object.assign(form, props.data, { score: parseInt(props.data.score) })
})
const rules = ref<FormRules>({
name: [{ required: true, message: '请输入模板名称' }],
type: [{ required: true, message: '请选择模板类型' }],
score: [{ required: true, message: '请输入不超过100的整数数值' }]
})
// 提交
function handleSubmit() {
formRef?.validate().then(() => (isUpdate ? handleUpdate() : handleCreate()))
}
// 新建
function handleCreate() {
const params = pick(form, ['name', 'type', 'score', 'is_view_answer', 'status'])
createTripTemplateList(params).then(() => {
ElMessage({ message: '创建成功', type: 'success' })
emit('update')
emit('update:modelValue', false)
})
}
// 修改
function handleUpdate() {
const params = pick(form, ['id', 'name', 'type', 'score', 'is_view_answer', 'status'])
updateTripTemplateList(params).then(() => {
ElMessage({ message: '修改成功', type: 'success' })
emit('update')
emit('update:modelValue', false)
})
}
</script>
<template>
<el-dialog :title="title" :close-on-click-modal="false" width="600px" @update:modelValue="$emit('update:modelValue')">
<el-form ref="formRef" :model="form" :rules="rules" label-suffix=":" label-width="170px">
<el-form-item label="模板名称" prop="name">
<el-input v-model="form.name" placeholder="请输入" />
</el-form-item>
<el-form-item label="模板类型" prop="type">
<el-select v-model="form.type" style="width: 100%">
<el-option v-for="item in tripTemplateTypeList" :key="item.value" v-bind="item"></el-option>
</el-select>
</el-form-item>
<el-form-item label="旅程分值" prop="score">
<el-input-number
v-model="form.score"
step-strictly
:min="0"
:max="100"
placeholder="请输入不超过100的整数数值"
style="width: 100%"></el-input-number>
</el-form-item>
<el-form-item label="是否允许学生查看解析" prop="is_view_answer">
<el-switch
v-model="form.is_view_answer"
active-text="允许"
active-value="1"
inactive-text="不允许"
inactive-value="0" />
</el-form-item>
<el-form-item label="状态" prop="status">
<el-switch v-model="form.status" active-text="生效" active-value="1" inactive-text="失效" inactive-value="0" />
</el-form-item>
</el-form>
<template #footer>
<el-row justify="center">
<el-button plain auto-insert-space @click="$emit('update:modelValue', false)">关闭</el-button>
<el-button type="primary" auto-insert-space @click="handleSubmit">保存</el-button>
</el-row>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import type { TripTemplate } from '../types'
import { useMapStore } from '@/stores/map'
import { getNameByValue, tripTemplateTypeList } from '@/utils/dictionary'
defineProps<{ data: TripTemplate }>()
const statusList = useMapStore().getMapValuesByKey('system_status')
</script>
<template>
<el-dialog title="查看旅程模板" width="600px">
<el-form ref="formRef" label-suffix=":">
<el-row justify="space-between">
<el-form-item label="模板名称" prop="name"> {{ data.name }} </el-form-item>
<el-form-item label="模板类型" prop="type">
{{ getNameByValue(data.type, tripTemplateTypeList) }}
</el-form-item>
<el-form-item label="旅程分值" prop="score"> {{ data.score }} </el-form-item>
</el-row>
<el-row justify="space-between">
<el-form-item label="是否允许学生查看解析" prop="is_view_answer">
<el-tag :type="data.is_view_answer === '1' ? 'success' : 'danger'">
{{ data.is_view_answer === '1' ? '允许' : '不允许' }}
</el-tag>
</el-form-item>
<el-form-item label="状态" prop="status">
<el-tag :type="data.status === '1' ? 'success' : 'danger'">
{{ getNameByValue(data.status, statusList) }}
</el-tag>
</el-form-item>
</el-row>
</el-form>
<template #footer>
<el-row justify="center">
<el-button plain auto-insert-space @click="$emit('update:modelValue', false)">关闭</el-button>
</el-row>
</template>
</el-dialog>
</template>
import type { Operator } from '@/types'
export interface TripTemplate {
id: string
name: string
type: string
status: string
score: string
is_view_answer: string
created_time: string
created_operator: Operator
updated_time: string
updated_operator: Operator
}
export type TripTemplateListRequest = Pick<TripTemplate, 'name' | 'type' | 'status'> & { experiment_id: string }
export type TripTemplateUpdateRequest = Pick<TripTemplate, 'id' | 'name' | 'type' | 'is_view_answer' | 'status'> & {
score: number
}
export type TripTemplateCreateRequest = Omit<TripTemplateUpdateRequest, 'id'>
<script setup lang="ts">
import type { TripTemplate } from '../types'
import { Plus } from '@element-plus/icons-vue'
import AppList from '@/components/base/AppList.vue'
import { ElMessageBox } from 'element-plus'
import { getTripTemplateList } from '../api'
import { useMapStore } from '@/stores/map'
import { getNameByValue, tripTemplateTypeList } from '@/utils/dictionary'
const FormDialog = defineAsyncComponent(() => import('../components/FormDialog.vue'))
const ViewDialog = defineAsyncComponent(() => import('../components/ViewDialog.vue'))
const statusList = useMapStore().getMapValuesByKey('system_status')
const appList = $ref<InstanceType<typeof AppList> | null>(null)
// 列表配置
const listOptions = computed(() => {
return {
filters: [{ type: 'input', prop: 'name', placeholder: '请输入旅程模板名称' }],
remote: {
httpRequest: getTripTemplateList,
params: { name: '', status: '', type: '' }
},
filters: [
{ type: 'input', prop: 'name', placeholder: '请输入旅程模板名称' },
{ type: 'select', prop: 'type', placeholder: '请选择旅程模板类型', options: tripTemplateTypeList },
{ type: 'select', prop: 'status', placeholder: '请选择旅程模板状态', options: statusList }
],
columns: [
{ label: '序号', type: 'index', width: 60 },
{ label: '模板名称', prop: 'id' },
{ label: '模板类型', prop: 'name' },
{ label: '用户旅程分值', prop: 'name' },
{ label: '状态', prop: 'name' },
{ label: '更新人', prop: 'name' },
{ label: '更新时间', prop: 'name' },
{ label: '模板名称', prop: 'name' },
{ label: '所属实验', prop: 'experiment.name' },
{
label: '模板类型',
prop: 'type',
computed({ row }: { row: TripTemplate }) {
return getNameByValue(row.type, tripTemplateTypeList)
}
},
{
label: '用户旅程分值',
prop: 'score',
computed({ row }: { row: TripTemplate }) {
return parseInt(row.score)
}
},
{ label: '状态', prop: 'status', slots: 'table-status' },
{ label: '更新人', prop: 'updated_operator.real_name' },
{ label: '更新时间', prop: 'updated_time' },
{ label: '操作', slots: 'table-x', width: 300 }
],
data: [{}, {}]
]
}
})
......@@ -25,6 +55,31 @@ const listOptions = computed(() => {
function handleRefresh() {
appList?.refetch()
}
let formVisible = $ref(false)
let currentRow = $ref<TripTemplate>()
// 新建
function handleAdd() {
formVisible = true
}
// 修改
function handleUpdate(row: TripTemplate) {
currentRow = row
formVisible = true
}
// 删除
function handleRemove(row: TripTemplate) {
ElMessageBox.confirm('确定要删除该旅程模板吗?', '提示').then(() => {
handleRefresh()
})
}
// 查看
let viewVisible = $ref(false)
function handleView(row: TripTemplate) {
currentRow = row
viewVisible = true
}
</script>
<template>
......@@ -32,16 +87,22 @@ function handleRefresh() {
<AppList v-bind="listOptions" ref="appList">
<template #header-buttons>
<el-space>
<el-button type="primary" :icon="Plus">新建</el-button>
<el-button type="primary" :icon="Plus" @click="handleAdd">新建</el-button>
</el-space>
</template>
<template #table-x>
<template #table-status="{ row }: { row: TripTemplate }">
<el-tag :type="row.status === '1' ? 'success' : 'danger'">{{ getNameByValue(row.status, statusList) }}</el-tag>
</template>
<template #table-x="{ row }: { row: TripTemplate }">
<el-button type="primary" plain>配置</el-button>
<el-button type="primary" plain>查看</el-button>
<el-button type="primary" plain>编辑</el-button>
<el-button type="primary" plain>删除</el-button>
<el-button type="primary" plain @click="handleView(row)">查看</el-button>
<el-button type="primary" plain @click="handleUpdate(row)">编辑</el-button>
<el-button type="primary" plain @click="handleRemove(row)">删除</el-button>
</template>
</AppList>
</AppCard>
<!-- 新建/修改 -->
<FormDialog v-model="formVisible" :data="currentRow" @update="handleRefresh" v-if="formVisible"></FormDialog>
<!-- 查看 -->
<ViewDialog v-model="viewVisible" :data="currentRow" v-if="viewVisible && currentRow"></ViewDialog>
</template>
......@@ -18,7 +18,12 @@ router.beforeEach(async (to, from, next) => {
user.isLogin ? next() : next('/401')
return
}
if (!to.query.experiment_id) {
to.query.experiment_id = '7028276368903241728'
next({ path: to.path, query: to.query })
} else {
next()
}
})
export default router
......@@ -74,3 +74,11 @@ export interface UserAttrRuleItem {
operate_name: string
value: string
}
export interface Operator {
avatar: string
id: string
nickname: string
real_name: string
username: string
}
......@@ -13,6 +13,8 @@ const httpRequest = axios.create({
// 请求拦截
httpRequest.interceptors.request.use(
function (config) {
if (config.params) config.params.experiment_id = '7028276368903241728'
if (config.data) config.data.experiment_id = '7028276368903241728'
return config
},
function (error) {
......
// json to array
export const json2Array = function (data: any, isValueToNumber = true) {
return Object.keys(data).map(value => ({ label: data[value], value: isValueToNumber ? parseInt(value) : value }))
export interface Dictionary {
label: string
value: string | number
}
export function getNameByValue(value: string | number, list: Dictionary[]) {
return list.find(item => item.value === value)?.label || value
}
// 旅程模板类型
export const tripTemplateTypeList = [
{ label: '自由旅程', value: '1' },
{ label: '固定旅程', value: '2' }
]
export const dateUnitList = [
{ label: '天', value: 1 },
{ label: '周', value: 2 },
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论