123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431 |
- <!--
- * @Author: fxs bjnsfxs@163.com
- * @Date: 2024-11-06
- * @LastEditors: fxs bjnsfxs@163.com
- * @LastEditTime: 2024-12-04
- * @Description:
- *
- -->
- <script setup lang="ts">
- import { FormFieldType } from '@/types/form'
- import type { FormField, ValueTypes } from '@/types/form'
- import { useRequest } from '@/hooks/useRequest'
- import { 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: 0, // 广告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: 'type',
- cnName: '广告类型',
- type: FormFieldType.SELECT,
- valueType: 'string',
- otherOptions: {
- placeholder: '请选择广告类型',
- options: [
- {
- label: '激活',
- value: 'active',
- name: 'active'
- },
- {
- label: '转化',
- value: 'conversion',
- name: 'conversion'
- }
- ]
- }
- },
- {
- name: 'aid',
- cnName: '广告ID',
- type: FormFieldType.INPUT,
- valueType: 'string'
- },
- {
- name: 'pid',
- cnName: '广告父ID',
- type: FormFieldType.INPUT,
- valueType: 'string'
- },
- {
- 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' }],
- pid: [
- { required: false, message: '广告父ID是可选项', trigger: 'blur' },
- { type: 'number', message: '广告父ID必须是数字', trigger: 'blur' }
- ],
- aid: [
- { 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']
- /**
- * 判断是否在安全整数范围内且不为NaN
- *
- * @param val 输入的数字
- */
- const isSafeInteger = (val: number) => {
- return val >= Number.MIN_SAFE_INTEGER && val <= Number.MAX_SAFE_INTEGER && !isNaN(val)
- }
- /**
- * 格式化数字输入
- *
- * 对于超出精度或者NaN的数字,自动设置为最大值
- *
- * @param val 输入的值
- */
- const formatInputNum = (val: string | number): number => {
- console.log(val)
- if (typeof val === 'number') return val
- let number = parseInt(val)
- if (!isSafeInteger(number)) {
- ElMessage.warning('超出安全整数范围,已自动设置为最大值')
- number = Number.MAX_SAFE_INTEGER
- }
- return number
- }
- /**
- * 格式化输入
- * @param val 值
- * @param valueType 值类型
- */
- const formatInput = (val: any, valueType: ValueTypes | undefined): any => {
- let newVal: any = ''
- if (valueType === 'int') {
- // 格式化为整数
- newVal = formatInputNum(val)
- }
- if (valueType === 'float') {
- const inputValue = parseFloat(val)
- newVal = isNaN(inputValue) ? 0 : inputValue
- }
- if (valueType === 'string') {
- // 直接返回字符串,去掉两边的空格
- newVal = String(val).trim()
- }
- return newVal // 默认返回原值
- }
- /**
- * 重置表单
- */
- const resetForm = () => {
- formRef.value?.resetFields()
- }
- /**
- * 提交表单
- * @param {*} formEl 表单实例
- */
- 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) {
- console.log(result.msg)
- return
- }
- ElMessage.success('设置成功')
- } catch (err) {
- ElMessage.error('设置失败')
- console.log(err)
- }
- } else {
- ElMessage.warning('请检查表单内容是否正确')
- }
- })
- }
- /**
- * 初始化表单数据,根据查询参数来
- */
- const initFormData = () => {
- let query = route.query
- if (Object.keys(query).length > 0) {
- for (let [k, v] of Object.entries(query)) {
- console.log(v)
- 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()
- </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="conditionTip">
- <span>以下参数为0则代表<span style="font-weight: bold">通用</span></span>
- </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]"
- :formatter="formatInputNum"
- />
- </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;
- }
- .conditionTip {
- padding: 0 24px;
- margin-top: 24px;
- font-size: 16px;
- color: #606266;
- }
- </style>
|