|
@@ -0,0 +1,386 @@
|
|
|
+<script setup lang="ts">
|
|
|
+import { FormFieldType } from '@/types/form'
|
|
|
+import type { FormField, ValueTypes } from '@/types/form'
|
|
|
+
|
|
|
+import { useRequest } from '@/hooks/useRequest'
|
|
|
+import { onMounted, reactive, ref } from 'vue'
|
|
|
+import { useCommonStore } from '@/stores/useCommon'
|
|
|
+import type { FormInstance, FormRules } from 'element-plus'
|
|
|
+import axiosInstance from '@/utils/axios/axiosInstance'
|
|
|
+import type { ResponseInfo } from '@/types/res'
|
|
|
+import { throttleFunc } from '@/utils/common'
|
|
|
+import { useRoute } from 'vue-router'
|
|
|
+import router from '@/router'
|
|
|
+
|
|
|
+const route = useRoute()
|
|
|
+const { selectInfo } = useCommonStore()
|
|
|
+
|
|
|
+interface FormData {
|
|
|
+ [key: string]: any
|
|
|
+ gid: string
|
|
|
+ aid: number | null
|
|
|
+ type: string
|
|
|
+ pid: number
|
|
|
+ start_num: number
|
|
|
+ revenue: number
|
|
|
+ duration: number
|
|
|
+ req_count: number
|
|
|
+ exp_count: number
|
|
|
+}
|
|
|
+
|
|
|
+const { AllApi } = useRequest()
|
|
|
+
|
|
|
+const formRef = ref<FormInstance>()
|
|
|
+
|
|
|
+// 是否是编辑状态进入
|
|
|
+const isEdit = ref<boolean>(false)
|
|
|
+
|
|
|
+// 现在进入的广告ID
|
|
|
+const nowAd = ref<string>('')
|
|
|
+
|
|
|
+const formData = ref<FormData>({
|
|
|
+ gid: selectInfo.gid, // 游戏Id
|
|
|
+ aid: null, // 广告ID
|
|
|
+ type: 'active', // 广告类型
|
|
|
+ pid: 0, // 广告父ID
|
|
|
+ start_num: 0, // 启动次数
|
|
|
+ revenue: 0.0, // 预估收益
|
|
|
+ duration: 0, // 在线时长(秒)
|
|
|
+ req_count: 0, // 观看广告次数
|
|
|
+ exp_count: 0 // 完整观看广告次数
|
|
|
+})
|
|
|
+
|
|
|
+const fieldsInfo: Array<FormField> = [
|
|
|
+ {
|
|
|
+ name: 'gid',
|
|
|
+ cnName: '游戏Id',
|
|
|
+ type: FormFieldType.INPUT,
|
|
|
+ valueType: 'string'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: 'aid',
|
|
|
+ cnName: '广告ID',
|
|
|
+ type: FormFieldType.INPUT,
|
|
|
+ valueType: 'int'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: 'type',
|
|
|
+ cnName: '广告类型',
|
|
|
+ type: FormFieldType.SELECT,
|
|
|
+ valueType: 'string',
|
|
|
+ otherOptions: {
|
|
|
+ placeholder: '请选择广告类型',
|
|
|
+ options: [
|
|
|
+ {
|
|
|
+ label: '激活',
|
|
|
+ value: 'active',
|
|
|
+ name: 'active'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: '转化',
|
|
|
+ value: 'conversion',
|
|
|
+ name: 'conversion'
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: 'pid',
|
|
|
+ cnName: '广告父ID',
|
|
|
+ type: FormFieldType.INPUT,
|
|
|
+ valueType: 'int'
|
|
|
+ },
|
|
|
+
|
|
|
+ {
|
|
|
+ name: 'start_num',
|
|
|
+ cnName: '启动次数',
|
|
|
+ type: FormFieldType.INPUT,
|
|
|
+ valueType: 'int'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: 'revenue',
|
|
|
+ cnName: '预估收益',
|
|
|
+ type: FormFieldType.INPUT,
|
|
|
+ valueType: 'float'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: 'duration',
|
|
|
+ cnName: '在线时长(秒)',
|
|
|
+ type: FormFieldType.INPUT,
|
|
|
+ valueType: 'int'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: 'req_count',
|
|
|
+ cnName: '观看广告次数',
|
|
|
+ type: FormFieldType.INPUT,
|
|
|
+ valueType: 'int'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: 'exp_count',
|
|
|
+ cnName: '完整观看广告次数',
|
|
|
+ type: FormFieldType.INPUT,
|
|
|
+ valueType: 'int'
|
|
|
+ }
|
|
|
+]
|
|
|
+
|
|
|
+const rules = reactive<FormRules<FormData>>({
|
|
|
+ gid: [{ required: true, message: '游戏Id是必填项', trigger: 'blur' }],
|
|
|
+ aid: [
|
|
|
+ { required: true, message: '广告ID是必填项', trigger: 'blur' },
|
|
|
+ { type: 'number', message: '广告ID必须是数字', trigger: 'blur' }
|
|
|
+ ],
|
|
|
+ pid: [
|
|
|
+ { required: false, message: '广告父ID是可选项', trigger: 'blur' },
|
|
|
+ { type: 'number', message: '广告父ID必须是数字', trigger: 'blur' }
|
|
|
+ ],
|
|
|
+ type: [
|
|
|
+ { required: true, message: '广告类型是必填项', trigger: 'trigger' },
|
|
|
+
|
|
|
+ {
|
|
|
+ validator: (_rule, value) =>
|
|
|
+ ['active', 'conversion'].includes(value) || '广告类型必须是 "active" 或 "conversion"',
|
|
|
+ trigger: 'blur'
|
|
|
+ }
|
|
|
+ ],
|
|
|
+ start_num: [
|
|
|
+ { required: false, message: '启动次数是可选项', trigger: 'blur' },
|
|
|
+ { type: 'number', message: '启动次数必须是数字', trigger: 'blur' }
|
|
|
+ ],
|
|
|
+ revenue: [
|
|
|
+ { required: false, message: '预估收益是可选项', trigger: 'blur' },
|
|
|
+ {
|
|
|
+ validator: (_rule, value, callback) => {
|
|
|
+ // 允许为空值,不进行验证
|
|
|
+ if (value === '' || value === null || value === undefined) {
|
|
|
+ callback() // 允许空值通过
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ // 检查是否为有效的浮动数值
|
|
|
+ const validFloatValue = /^(\d+(\.\d+)?|\.\d+)$/.test(value)
|
|
|
+ if (!validFloatValue) {
|
|
|
+ callback(new Error('预估收益必须是有效的数字'))
|
|
|
+ } else {
|
|
|
+ callback() // 验证通过
|
|
|
+ }
|
|
|
+ },
|
|
|
+ trigger: 'blur'
|
|
|
+ }
|
|
|
+ ],
|
|
|
+ duration: [
|
|
|
+ { required: false, message: '在线时长是可选项', trigger: 'blur' },
|
|
|
+ { type: 'number', message: '在线时长必须是数字', trigger: 'blur' }
|
|
|
+ ],
|
|
|
+ req_count: [
|
|
|
+ { required: false, message: '观看广告次数是可选项', trigger: 'blur' },
|
|
|
+ { type: 'number', message: '观看广告次数必须是数字', trigger: 'blur' }
|
|
|
+ ],
|
|
|
+ exp_count: [
|
|
|
+ { required: false, message: '完整观看广告次数是可选项', trigger: 'blur' },
|
|
|
+ { type: 'number', message: '完整观看广告次数必须是数字', trigger: 'blur' }
|
|
|
+ ]
|
|
|
+})
|
|
|
+
|
|
|
+// 编辑页面不能修改的字段
|
|
|
+const disableEditField = ['pid', 'gid', 'aid', 'type']
|
|
|
+
|
|
|
+/**
|
|
|
+ * @description: 格式化输入,主要是对数字处理
|
|
|
+ * @param {*} val 值
|
|
|
+ * @param {*} key 键
|
|
|
+ * @param {*} valueType 值类型
|
|
|
+ * @return {*}
|
|
|
+ */
|
|
|
+const formatInput = (val: any, valueType: ValueTypes | undefined): any => {
|
|
|
+ let newVal: any = ''
|
|
|
+ if (valueType === 'int') {
|
|
|
+ // 格式化为整数
|
|
|
+ const intValue = parseInt(val, 10)
|
|
|
+ newVal = isNaN(intValue) ? 0 : intValue // 如果转换失败,则返回 null
|
|
|
+ }
|
|
|
+
|
|
|
+ if (valueType === 'float') {
|
|
|
+ const inputValue = parseFloat(val)
|
|
|
+ newVal = isNaN(inputValue) ? 0 : inputValue
|
|
|
+ }
|
|
|
+
|
|
|
+ if (valueType === 'string') {
|
|
|
+ // 直接返回字符串,去掉两边的空格
|
|
|
+ newVal = String(val).trim()
|
|
|
+ }
|
|
|
+
|
|
|
+ return newVal // 默认返回原值
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * @description: 重置表单
|
|
|
+ * @return {*}
|
|
|
+ */
|
|
|
+const resetForm = () => {
|
|
|
+ formRef.value?.resetFields()
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * @description: 提交表单
|
|
|
+ * @param {*} formEl 表单实例
|
|
|
+ * @return {*}
|
|
|
+ */
|
|
|
+const subForm = (formEl: FormInstance | undefined) => {
|
|
|
+ if (!formEl) return
|
|
|
+
|
|
|
+ formEl.validate(async (valid) => {
|
|
|
+ if (valid) {
|
|
|
+ try {
|
|
|
+ // 转为对应类型
|
|
|
+ for (let [k, v] of Object.entries(formData.value)) {
|
|
|
+ let valueType = fieldsInfo.find((item) => item.name === k)?.valueType
|
|
|
+ formData.value[k] = formatInput(v, valueType)
|
|
|
+ }
|
|
|
+ let result = (await axiosInstance.post(
|
|
|
+ AllApi.setGameCondition,
|
|
|
+ formData.value
|
|
|
+ )) as ResponseInfo
|
|
|
+ if (result.code !== 0) {
|
|
|
+ throw new Error(result.msg)
|
|
|
+ }
|
|
|
+ ElMessage.success('设置成功')
|
|
|
+ } catch (err) {
|
|
|
+ ElMessage.error('设置失败')
|
|
|
+ console.log(err)
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ ElMessage.warning('请检查表单内容是否正确')
|
|
|
+ }
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * @description: 初始化表单数据,根据查询参数来
|
|
|
+ * @return {*}
|
|
|
+ */
|
|
|
+const initFormData = () => {
|
|
|
+ let query = route.query
|
|
|
+ if (Object.keys(query).length > 0) {
|
|
|
+ for (let [k, v] of Object.entries(query)) {
|
|
|
+ if (k !== 'head')
|
|
|
+ formData.value[k] = formatInput(v, fieldsInfo.find((item) => item.name === k)?.valueType)
|
|
|
+ }
|
|
|
+ nowAd.value = query.aid as string
|
|
|
+ isEdit.value = true
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+const throttleSub = throttleFunc(subForm, 1000)
|
|
|
+const throttleReset = throttleFunc(resetForm, 1000)
|
|
|
+
|
|
|
+const goBack = () => {
|
|
|
+ router.push('/appManage/userConversion')
|
|
|
+}
|
|
|
+initFormData()
|
|
|
+
|
|
|
+onMounted(() => {})
|
|
|
+</script>
|
|
|
+
|
|
|
+<template>
|
|
|
+ <div class="conditionContainer">
|
|
|
+ <div class="conditionHeader">
|
|
|
+ <el-page-header @back="goBack">
|
|
|
+ <template #content>
|
|
|
+ <span class="text-large font-600 mr-3" style="font-weight: 600">
|
|
|
+ {{ nowAd || '新增' }}
|
|
|
+ </span>
|
|
|
+ </template>
|
|
|
+ </el-page-header>
|
|
|
+ </div>
|
|
|
+ <div class="conditionBody">
|
|
|
+ <el-form
|
|
|
+ ref="formRef"
|
|
|
+ :model="formData"
|
|
|
+ :rules="rules"
|
|
|
+ label-width="auto"
|
|
|
+ status-icon
|
|
|
+ :inline="true"
|
|
|
+ >
|
|
|
+ <template v-for="item in fieldsInfo" :key="item.name">
|
|
|
+ <el-form-item
|
|
|
+ style="width: 350px"
|
|
|
+ v-if="item.type === FormFieldType.INPUT"
|
|
|
+ :label="item.cnName"
|
|
|
+ :prop="item.name"
|
|
|
+ >
|
|
|
+ <el-input
|
|
|
+ v-if="item.valueType === 'string' || item.valueType === 'float'"
|
|
|
+ :disabled="(disableEditField.includes(item.name) && isEdit) || item.name === 'gid'"
|
|
|
+ v-model="formData[item.name]"
|
|
|
+ />
|
|
|
+ <el-input
|
|
|
+ v-else
|
|
|
+ :disabled="(disableEditField.includes(item.name) && isEdit) || item.name === 'gid'"
|
|
|
+ v-model.number="formData[item.name]"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item
|
|
|
+ :label="item.cnName"
|
|
|
+ :prop="item.name"
|
|
|
+ v-if="item.type === FormFieldType.SELECT"
|
|
|
+ style="width: 350px"
|
|
|
+ >
|
|
|
+ <el-select
|
|
|
+ v-model="formData[item.name]"
|
|
|
+ :label="item.cnName"
|
|
|
+ :placeholder="item.otherOptions?.placeholder"
|
|
|
+ :disabled="(disableEditField.includes(item.name) && isEdit) || item.name === 'gid'"
|
|
|
+ size="default"
|
|
|
+ >
|
|
|
+ <el-option
|
|
|
+ v-for="option in item.otherOptions?.options"
|
|
|
+ :key="option.name"
|
|
|
+ :label="option.label"
|
|
|
+ :value="option.value"
|
|
|
+ />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ </template>
|
|
|
+ </el-form>
|
|
|
+ <div class="formBtnGroup">
|
|
|
+ <el-button class="handleBtn" @click="throttleReset" plain color="#626aef">重置</el-button>
|
|
|
+ <el-button class="handleBtn" @click="throttleSub(formRef)" color="#626aef">提交</el-button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<style scoped>
|
|
|
+.conditionContainer {
|
|
|
+ width: 98%;
|
|
|
+ margin: 1% auto;
|
|
|
+ box-sizing: border-box;
|
|
|
+}
|
|
|
+
|
|
|
+.conditionBody {
|
|
|
+ box-sizing: border-box;
|
|
|
+ margin-top: 15px;
|
|
|
+ padding: 24px;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ width: 100%;
|
|
|
+ position: relative;
|
|
|
+ background-color: white;
|
|
|
+ box-shadow:
|
|
|
+ 0 4px 8px 0 rgba(0, 0, 0, 0.02),
|
|
|
+ 0 1px 3px 0 rgba(0, 0, 0, 0.02);
|
|
|
+}
|
|
|
+
|
|
|
+.formBtnGroup {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+}
|
|
|
+
|
|
|
+.handleBtn {
|
|
|
+ margin-bottom: 18px;
|
|
|
+}
|
|
|
+
|
|
|
+.conditionHeader {
|
|
|
+ padding: 0 24px;
|
|
|
+}
|
|
|
+</style>
|