在Flex中用Validator检测数字、字符串、Email、电话号码等 .

本文介绍了在Flex中使用Validator进行复杂数据验证的方法,包括字符串长度限制、数字范围检查及电子邮件格式验证等,并提供了详细的代码示例。
在Flex中用Validator检测数字、字符串、Email、电话号码等
在上例“ 用Validator检测必填项”中,我记录了Validator最简单的用法。但mx.validators包中的类并非只有Validator一个,他们可以实现信用卡号码格式检测(mx.validators.CreditCardValidator)、货币格式检测(mx.validators.CurrencyValidator)、E-mail格式检测(mx.validators.EmailValidator)等等功能,所有的检测器列表可以看这里。这些类都是Validator的子类。

先看效果。下面的范例演示了StringValidator、NumberValidator和EmailValidator的用法。由于这三个类都继承自Validator,因此都拥有requiredFieldError属性,用于自定义没有值的时候的错误信息。但是这三个类拥有更多的错误信息。要检测的值越复杂,需要定义的错误信息就越多,例如EmailValidator,本例中共定义了9个错误信息。

如果不定义错误信息,Flex会显示默认的英文错误信息,这显然也不是我们所需要的。如果想偷懒的话,可以定义几个最可能出现的错误,例如本例的NumberValidator,就没有定义所有的错误信息。

顺便还要说一句的是,NumberValidator可以指定要检测的数字是整数还是实数,这需要用domain属性来指定。同时,它还可以指定千分位分隔符。

<?xml version="1.0" encoding="utf-8"?>

<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" fontSize="12" width="300" height="200">

 <mx:Style>
 <![CDATA[
 .errorTip
 {
 fontSize: 12;
 }
 ]]>
 </mx:Style>

 <mx:StringValidator id="nameV" source="{nameTI}" property="text"
 minLength="2"
 maxLength="5" 
 requiredFieldError="必须输入姓名!"
 tooShortError="姓名过短!"
 tooLongError="姓名过长!"
 trigger="{btn}" triggerEvent="click"/>

 <mx:NumberValidator id="ageV" source="{ageTI}" property="text"
 domain="int"
 minValue="6"
 maxValue="100"
 lowerThanMinError="年龄过小!"
 exceedsMaxError="年龄过大!" 
 integerError="年龄必须是整数!"
 invalidCharError='输入了非数字字符!'
 requiredFieldError="必须输入年龄!"
 trigger="{btn}" triggerEvent="click"/>

 <mx:Validator id="sexV" source="{sexRBG}" property="selectedValue" 
 requiredFieldError="必须选择性别!"
 trigger="{btn}" triggerEvent="click"
 listener="{maleRB}"/>

 <mx:EmailValidator id="emailV" source="{emailTI}" property="text"
 requiredFieldError="必须输入E-mail"
 invalidCharError="E-mail地址中有错误字符。"
 invalidDomainError="E-mail地址中的域名不符合规范。"
 invalidIPDomainError="E-mail地址中的IP格式域名不符合规范。"
 invalidPeriodsInDomainError="域名中的“.”错误。"
 missingAtSignError="E-mail地址缺少“@”符号。"
 missingPeriodInDomainError="域名中缺少“.”"
 missingUsernameError="E-mail地址缺少用户名。"
 tooManyAtSignsError="E-mail地址中的“@”符号太多。"
 trigger="{btn}" triggerEvent="click"/>
 
 <mx:FormItem label="姓名:" width="200">
 <mx:TextInput id="nameTI"/>
 </mx:FormItem>

 <mx:FormItem label="年龄:" width="200">
 <mx:TextInput id="ageTI"/>
 </mx:FormItem>

 <mx:FormItem label="性别:" direction="horizontal" width="200">
 <mx:RadioButtonGroup id="sexRBG"/>
 <mx:RadioButton id="maleRB" groupName="sexRBG" label="男" value="1"/>
 <mx:RadioButton id="femaleRB" groupName="sexRBG" label="女" value="0"/>
 </mx:FormItem>

 <mx:FormItem label="E-mail:" width="200">
 <mx:TextInput id="emailTI"/>
 </mx:FormItem>

 <mx:Button id="btn" label="提交" />


<template> <el-form ref="ruleFormRef" style="margin-top: 20px;max-width: 600px" :model="ruleForm" :rules="rules" label-width="auto"> <el-form-item label="产品名称:" prop="name"> <el-input v-model="ruleForm.name" /> </el-form-item> <el-form-item label="产品描述:" prop="description"> <el-input v-model="ruleForm.description" type="textarea"/> </el-form-item> <el-form-item label="产品分类:" prop="category" style="width: 50%;"> <el-select v-model="ruleForm.category" placeholder="请选择分类"> <el-option v-for="item in categorys" :label="item.name" :value="item.id" :key="item.id" /> </el-select> </el-form-item> <el-form-item label="产品单价:" prop="price"> <el-input v-model.number="ruleForm.price" type="number" style="width: 240px" /> </el-form-item> <el-form-item label="产品库存:" prop="stock"> <el-input v-model.number="ruleForm.stock" type="number" style="width: 240px" /> </el-form-item> <el-form-item label="生产厂家:" prop="manufacturer"> <el-input v-model="ruleForm.manufacturer" /> </el-form-item> <el-form-item label="产地:" required> <el-col :span="12"> <el-form-item prop="originProvince"> <el-select v-model="ruleForm.originProvince" placeholder="省" style="flex: 1; margin-right: 10px"> <el-option v-for="item in originProvinces" :key="item.id" :label="item.name" :value="item.id" /> </el-select> </el-form-item> </el-col> <el-col :span="12"> <el-form-item prop="originCity"> <el-select v-model="ruleForm.originCity" placeholder="市" style="flex: 1 " :disabled="!ruleForm.originProvince"> <el-option v-for="item in originCitys" :key="item.id" :label="item.name" :value="item.id" /> </el-select> </el-form-item> </el-col> </el-form-item> <el-form-item label="发货地:" required> <el-col :span="12"> <el-form-item prop="shippingProvince"> <el-select v-model="ruleForm.shippingProvince" placeholder="省" style="flex: 1; margin-right: 10px"> <el-option v-for="item in originProvinces" :key="item.id" :label="item.name" :value="item.id" /> </el-select> </el-form-item> </el-col> <el-col :span="12"> <el-form-item prop="shippingCity"> <el-select v-model="ruleForm.shippingCity" placeholder="市" style="flex: 1" :disabled="!ruleForm.shippingProvince"> <el-option v-for="item in shippingCities" :key="item.id" :label="item.name" :value="item.id" /> </el-select> </el-form-item> </el-col> </el-form-item> <el-form-item label="生产日期" required> <el-col :span="11"> <el-form-item prop="createAt"> <el-date-picker v-model="ruleForm.createAt" type="date" aria-label="Pick a date" placeholder="Pick a date" style="width: 100%" /> </el-form-item> </el-col> </el-form-item> <el-form-item> <!-- 登录按钮:仅在默认模式下显示 --> <el-button v-if="pageMode === 'default'" style="margin-left: 18px;" type="primary" @click="submitForm(ruleFormRef, ruleForm)"> 登录 </el-button> <!-- 更新按钮:仅在编辑模式下显示 --> <el-button v-if="pageMode === 'edit'" style="margin-left: 30px;" type="primary" @click="updateForm(ruleFormRef)"> 更新 </el-button> <!-- 重置按钮:在编辑或默认模式下都显示 --> <el-button v-if="pageMode === 'edit' || pageMode === 'default'" style="margin-left: 30px;" type="primary" @click="resetForm(ruleFormRef)"> 重置 </el-button> </el-form-item> </el-form> </template> <script setup> import { ref, reactive, onMounted } from 'vue'; import productApi from '@/api/products' import placeApi from '@/api/place' import { useRouter } from 'vue-router' import { ElLoading, ElMessage } from 'element-plus' const pageMode = ref('') // 可选值: 'view', 'edit', 'default' const router = useRouter(); const ruleFormRef = ref() const categorys = ref([])// 产品分类 const originProvinces = ref([]) // 省份数据 const originCitys = ref([]) // 城市数据 const shippingCities = ref([]) // 发货地城市数据 const ruleForm = reactive({ name: '', description: '', category: '', price: '', stock: '', manufacturer: '', originProvince: '', originCity: '', shippingProvince: '', shippingCity: '', createAt: '', user: 'aaa', delivery: false, type: [], }) const rules = reactive({ name: [ { required: true, message: '请输入商品名称', trigger: 'blur' }, { max: 10, message: '长度超过10位', trigger: 'blur' }, ], description: [ { required: true, message: '请输入商品描述', trigger: 'blur' }, { max: 200, message: '长度超过200位', trigger: 'blur' }, ], category: [ { required: true, message: '请选择分类', trigger: 'change', }, ], price: [ { required: true, message: '请输入商品单价', trigger: ['blur', 'change'] }, { type: 'number', message: '请输入有效的数字', trigger: ['blur', 'change'] }, { validator: (rule, value, callback) => { if (value === null || value === '') { callback(new Error('请输入商品单价')) } else if (value <= 0) { callback(new Error('单价必须大于 0')) } else if (value > 10000) { callback(new Error('单价不能大于 10000')) } else { callback() } }, trigger: ['blur', 'change'] } ], stock: [ { required: true, message: '请输入商品单价', trigger: ['blur', 'change'] }, { type: 'number', message: '请输入有效的数字', trigger: ['blur', 'change'] }, { validator: (rule, value, callback) => { if (value === null || value === '') { callback(new Error('请输入商品单价')) } else if (value <= 0) { callback(new Error('单价必须大于 0')) } else if (value > 10000) { callback(new Error('单价不能大于 10000')) } else { callback() } }, trigger: ['blur', 'change'] } ], manufacturer: [ { required: true, message: '请输入生产厂家', trigger: 'blur' }, ], shippingProvince: { validator: (rule, value, callback) => { if (!value) { callback(new Error('请选择发货省份')) } else { callback() } }, trigger: 'change' }, shippingCity:{ validator: (rule, value, callback) => { if (!value) { callback(new Error('请选择发货城市')) } else { callback() } }, trigger: 'change' }, originProvince: { validator: (rule, value, callback) => { if (!value) { callback(new Error('请选择发货省份')) } else { callback() } }, trigger: 'change' }, originCity:{ validator: (rule, value, callback) => { if (!value) { callback(new Error('请选择发货城市')) } else { callback() } }, trigger: 'change' }, createAt: [ { type: 'date', required: true, message: 'Please pick a date', trigger: 'change', }, ], type: [ { type: 'array', required: true, message: 'Please select at least one activity type', trigger: 'change', }, ], }) // 表单操作 const resetForm = (formEl) => { if (!formEl) return formEl.resetFields() } //产品分类 function getCategory() { productApi.getCategory().then(res => { categorys.value = res.data; }) } // 获取省份 function getProvinces() { placeApi.getProvince().then(res => { originProvinces.value = res.data }).catch(error => { console.error('获取省份失败:', error) }) } // 获取商品详情 function getProductDetail(productId) { productApi.getById(productId).then(res => { const data = res.data // 先赋值整个对象 Object.assign(ruleForm, data) }).catch(error => { console.error('获取商品详情失败:', error); }); } // 监听产地省份变化,加载城市 watch( () => ruleForm.originProvince, (newVal) => { if (newVal) { placeApi.getCity(newVal).then(res => { originCitys.value = res.data }).catch(() => { originCitys.value = [] }) } else { originCitys.value = [] ruleForm.originCity = '' } } ) // 监听发货地省份变化,加载城市 watch( () => ruleForm.shippingProvince, (newVal) => { if (newVal) { placeApi.getCity(newVal).then(res => { shippingCities.value = res.data }).catch(() => { shippingCities.value = [] }) } else { shippingCities.value = [] ruleForm.shippingCity = '' } } ) // 更新操作 const updateForm = async (formEl) => { if (!formEl) return const loading = ElLoading.service({ fullscreen: true }) await formEl.validate((valid, fields) => { if (valid) { console.log('开始提交...') // 调用 API 更新商品信息 productApi.update(ruleForm).then(res => { ElMessage.success('更新成功') router.push('/home/test1') // 可选跳转回列表页 }).catch(error => { ElMessage.error('更新失败,请重试') }).finally(() => { loading.close() }) } else { console.log('表单验证失败:', fields) ElMessage.error('请检查输入内容') loading.close() return false } }) } // 登录操作 const submitForm = async (formEl, ruleForm) => { if (!formEl) return await formEl.validate((valid, fields) => { if (valid) { console.log('开始提交商品...') const loading = ElLoading.service({ fullscreen: true }) productApi.addProduct(ruleForm).then(res => { ElMessage.success('保存成功') router.push('/home/test1') }).catch(error => { ElMessage.error('保存失败,请重试') }).finally(() => { loading.close() }) } else { console.log('表单验证失败:', fields) ElMessage.error('请检查输入内容') loading.close() return false } }) } onMounted(() => { getCategory() getProvinces() const route = router.currentRoute.value const type = route.query.type const productId = route.params.id || route.query.id if (type === 'view') { pageMode.value = 'view' // 查看模式:不显示按钮 } else if (type === 'edit') { pageMode.value = 'edit' // 编辑模式:显示“更新”、“重置” } else { pageMode.value = 'default' // 默认模式:显示“登录”、“重置” } if (productId) { getProductDetail(productId) } }) </script> <style> .location-selectors { display: flex; justify-content: space-between; width: 100%; } </style>
07-15
import { useBaseFormTemplateMethods } from "@/template/BaseFormTemplate/hooks"; export const useBaseFormTemplate = (refName: string, interAction?: any) => { const config = reactive({ lifeCycle: { mountedTemplate: () => { interAction.mountedTemplate(); }, }, header: { backBar: true, titleBar: { label: () => { return interAction.getTitle(); }, }, buttonList: [ { label: "button.submit", onClick: () => { interAction.onClickSubmit(); }, validator: () => { return { show: !interAction.isEdit(), disabled: false }; }, }, { label: "button.submit", onClick: () => { interAction.onClickSubmit(); }, validator: () => { return { show: interAction.isEdit(), disabled: false }; }, }, ], }, form: { onChangeEvent: (value: string, component: any) => { interAction.onChangeEvent(value, component); }, value: { name: "", // deviceType: "", // deviceModel: [], // file: [], description: "", }, components: [ { name: "label.thing-icon-store-name", type: "input", value: "name", required: true, popover: (component: any, index: number) => { return true; }, popoverAttribute: (component: any) => { return { popContent: interAction.getThingIconNamePopoverContent(), }; }, attribute: (component: any) => { return { formatter: (value: any) => { return value; }, parser: (value: any) => { return value.replace(/[^a-zA-Z0-9\u4e00-\u9fa5_.]/g, ""); }, props: { placeholder: "Please Input Icon Name", }, }; }, }, { name: "label.thing-icon-store-deviceType", value: "deviceType", type: "cascader", required: true, fullLine: true, attribute: () => { return { filterable: true, options: interAction.getThingTypeTree(), props: { multiple: false, }, disabled: interAction.disabledThingType(), // onChange: (value: any) => { // console.log('modelValue changed:', value); // } }; }, }, { name: "label.thing-icon-store-deviceModel", type: "cascader", value: "deviceModel", required: true, attribute: (component: any) => { return { options: interAction.getDeviceModelList(), disabled: interAction.disabledThingTypeModel(), props: { multiple: true, emitPath: false, }, }; }, // type: "select", // value: "deviceModel", // required: true, // attribute: (component: any) => ({ // return { // options: interAction.getDeviceModelList(), // disabled: interAction.disabledThingTypeModel(), // }; // }), }, { type: "upload", name: "label.thing-icon-store-upload", value: "file", required: true, // popover: (component: any, index: number) => { // return true; // }, // popoverAttribute: (component: any) => { // return { // popContent: interAction.getIconUploadPopoverContent(), // }; // }, uploadAttribute: (component: any) => { return interAction.upload(); }, }, { name: "label.thing-icon-store-current-icon", type: "custom", value: "currentIconPreview", // 只是一个占位标识 show: () => { console.log("[Debug] isEdit:", interAction.isEdit()); // 看输出是否符合预期 return interAction.isEdit(); }, }, { name: "label.thing-icon-store-description", type: "input", value: "description", required: true, attribute: (component: any) => { return { type: "textarea", maxlength: 500, showWordLimit: true, autosize: { minRows: 6, maxRows: 6 }, }; }, }, ], }, }); return { config, template: useBaseFormTemplateMethods(refName) }; }; ts文件 <template> <BaseFormTemplate ref="BaseFormTemplate" :config="config"></BaseFormTemplate> <!-- 编辑模式下显示图片预览 --> <!-- <div v-if="isEdit()" class="image-preview-container"> <label class="form-label">{{ $t("label.thing-icon-store-current-icon") }}</label> <el-image v-if="detailObject.value?.fileUrl" :src="detailObject.value?.fileUrl" :alt="$t('label.thing-icon-store-current-icon')" fit="contain" style="width: 100px; height: 100px; border: 1px solid #ddd; padding: 5px" :preview-src-list="[detailObject.value?.fileUrl]" > <template #error> <div class="image-error-slot"> {{ $t("message.image-load-failed") }} </div> </template> </el-image> <span v-else class="no-image-text">{{ $t("message.no-image") }}</span> </div> --> </template> <script setup lang="ts"> import { useBaseFormTemplate } from "./hooks"; import { getDeviceTypeThingIconStoreModel, iconStoreDetails, iconStoreSubmit, iconStoreUpdateIcon, } from "@/api/iot-thing-map/thing-icon-store.api"; import { apiThingTypeList, apiThingTypeTree, } from "@/api/iot-thing-model/thing-type.api"; // import { // apiGetThingModel, // apiCreateThingModel, // apiEditThingModel, // apiGenerateIndent // } from "@/api/iot-thing-model/thing-model-store.api"; /*****************Template+Hooks*****************/ const interAction = { onClickSubmit, getTitle, getThingIconNamePopoverContent, getThingIconDeviceTypePopoverContent, getThingIconDeviceModelPopoverContent, getIconUploadPopoverContent, onChangeEvent, mountedTemplate, isEdit, getThingTypeTree, disabledThingType, getThingTypeModelTree, getDeviceModelList, disabledThingTypeModel, upload, onUploadFileSuccess, onFormUploadFileChange, onUploadFileError, onUploadFileRemove, onUploadFilePreview, }; const { config, template } = useBaseFormTemplate( "BaseFormTemplate", interAction ); /********************Variable********************/ const route = useRoute(); const { proxy } = getCurrentInstance(); const detailObject = ref({}); const thingTypeTree = ref([]); const hasData = ref(0); const modelId = ref<{ value: string }>; // 定义 deviceModelOptions 并初始化为空数组 const deviceModelOptions = ref<any>([]); // 定义 deviceType:二维字符串数组 const deviceType = ref<string[][]>([]); const deviceModel = ref<string[]>([]); const { VITE_APP_API_BASE_FILE } = import.meta.env; const filePathArr = ref([]); const uploadFileFlag = ref(false); /********************Function********************/ function getTitle() { return isEdit() ? "menu.iot-thing-map.edit-thing-icon" : "menu.iot-thing-map.add-thing-icon"; } function mountedTemplate() { initThingTypeTree(); if (isEdit()) { executeApiGetDetail(); } else { generateIndent(); } } function initThingTypeTree() { apiThingTypeTree({}) .then((res) => { thingTypeTree.value = res; }) .catch((err) => {}); } function disabledThingType() { if (hasData.value == 1) { return true; } else { return false; } } function getThingTypeTree() { return thingTypeTree.value; } function executeApiGetDetail() { template.showLoading(); iconStoreDetails({ iconId: template.getRoute().query.id }) .then((res) => { const tt = res.thingType; if (!tt || !tt.productLineDictId || !tt.id) return null; deviceType.value = [tt.productLineDictId, tt.id]; const ids: string[] = []; getDeviceTypeThingIconStoreModel({ thingTypeId: tt.id }).then( (response) => { const deciveModelList: { label: string; value: number }[] = []; response.forEach((e: { id: number; name: string }) => { deciveModelList.push({ label: e.model, value: e.id, }); }); deviceModelOptions.value = deciveModelList; } ); res.thingTypeModelList.forEach((item) => { if (item.id) { ids.push(item.id); } }); deviceModel.value = ids; detailObject.value = { ...res }; if (res.fileUrl) { config.form.value.file = res.fileUrl; filePathArr.value = [res.fileUrl]; } template.getValues().name = res.iconName; template.getValues().deviceType = deviceType.value; template.getValues().deviceModel = deviceModel.value; template.getValues().description = res.description; template.hideLoading(); }) .catch((err) => { template.hideLoading(); }); } function isEdit() { // return route.query.id != undefined; console.log('id',route.query.id) if(route.query.id != undefined) { console.log('1') return true } else { console.log('2') return false } } function getThingIconNamePopoverContent() { return proxy.$t("message.create.thing.icon.store.name"); } function getThingIconDeviceTypePopoverContent() { return proxy.$t("message.create.thing.icon.store.deviceType"); } function getThingIconDeviceModelPopoverContent() { return proxy.$t("message.create.thing.icon.store.deviceModel"); } function getIconUploadPopoverContent() { return proxy.$t("message.create.thing.icon.store.upload"); } function onChangeEvent(value: string, component: any) { switch (component.value) { case "deviceType": // console.log("value", value); if (!value || (Array.isArray(value) && value.length === 0)) { // console.log("❌ 未选择任何值"); return; } let targetNode: TreeNode | undefined = undefined; // 如果是数组,则按层级路径查找 if (Array.isArray(value)) { // console.log("📎 收到路径数组:", value); let currentNodes: TreeNode[] = thingTypeTree.value; for (const levelValue of value) { const matchedNode = currentNodes?.find( (node) => node.value === levelValue ); if (!matchedNode) { console.error(`❌ 在当前层级找不到 value="${levelValue}" 的节点`); return; } targetNode = matchedNode; // 进入下一层级 currentNodes = (matchedNode.children as TreeNode[]) ?? []; } } else { // 单值情况(非级联) const findInTree = (nodes: TreeNode[]): TreeNode | undefined => { for (const node of nodes) { if (node.value === value) return node; if (node.children && Array.isArray(node.children)) { const found = findInTree(node.children); if (found) return found; } } return undefined; }; targetNode = findInTree(thingTypeTree.value); } if (targetNode) { // console.log("✅ 成功找到目标节点:", targetNode.value); modelId.value = targetNode.value; // console.log("targetNode.value", modelId.value); // 可用于后续操作:设置图标、更新表单等 getThingTypeModelTree(); } else { // console.error("❌ 未找到匹配节点"); } break; case "deviceModel": // console.log("maodel value",value) } } function getThingTypeModelTree() { getDeviceTypeThingIconStoreModel({ thingTypeId: modelId.value }) .then((res) => { // console.log('res',res) const deciveModelList: { label: string; value: number }[] = []; res.forEach((e: { id: number; name: string }) => { deciveModelList.push({ label: e.model, value: e.id, }); }); deviceModelOptions.value = deciveModelList; }) .catch((err) => {}); } function getDeviceModelList() { // console.log("deciveModelList", deviceModelOptions.value); return deviceModelOptions.value; } function disabledThingTypeModel() { if (deviceModelOptions.value.length == 0) { return true; } else { return false; } } function upload() { return { ref: "uploadFile", url: VITE_APP_API_BASE_FILE + "/api/v1/aliyun-oss/uploadSimpleFile", data: { module: "iconStore", }, disabled: false, multiple: false, // suffix: ["xls", "xlsx"], suffix: ["png", "jpg", "jpeg", "gld", "gltf"], name: "file", buttonUpload: "button.selectFile", popover: true, popoverAttribute: { popContent: proxy.$t("message.create.thing.icon.store.upload"), }, showNotification: false, useContentSlot: true, size: 10, unit: "MB", autoUpload: false, limit: 1, onUploadSuccess: (response: any, file: any, fileList: any) => { // ✅ 处理上传成功的响应 if (response?.code === 0 || response?.success) { const fileUrl = response.data?.url; if (fileUrl) { config.form.value.file = fileUrl; // 存入表单 filePathArr.value = [fileUrl]; // 可选:维护一个数组 proxy.$message.success("上传成功"); } } else { proxy.$message.error(response.message || "上传失败"); onUploadFileError({ response, file, fileList }); } }, onUploadError: (err: any) => { uploadFileFlag.value = false; proxy.$message.error("文件上传出错"); }, onRemoveChange: () => { config.form.value.file = ""; // 清除表单值 filePathArr.value = []; }, onFormUploadChange: (fileList: any) => { interAction.onFormUploadFileChange(fileList); }, onUploadPreview: () => { interAction.onUploadFilePreview(); }, }; } function onUploadFileSuccess(response: any, file: any, fileList: any) { if (response?.code === 0 && response.data?.url) { config.form.value.file = response.data.url; filePathArr.value.push(response.data.url); proxy.$message.success("上传成功"); } else { proxy.$message.error(response.message || "上传失败"); } } function onFormUploadFileChange(files: any) { // isUpdateFile.value = true; console.log(files); } function onUploadFileError(files: any) { uploadFileFlag.value = false; } function onUploadFileRemove() {} function onUploadFilePreview() {} function generateIndent() { // template.showLoading(); // apiGenerateIndent({}) // .then((res) => { // template.getValues().ident = res; // template.hideLoading(); // }) // .catch((err) => { // template.hideLoading(); // }); } function submitForm() {} function onClickSubmit() { template.validate().then((result: any) => { template.showLoading(); // console.log('Submit',isEdit()); if (isEdit()) { // console.log("Edit", template.getValues()); const params = { id: route.query.id, iconName: template.getValues().name, typeId: modelId.value, modelIdList: template.getValues().deviceModel, fileUrl: config.form.value.file, // ✅ 改为动态获取上传结果 // fileUrl: "jichufivewife1.png", description: template.getValues().description, }; iconStoreUpdateIcon(params) .then((res) => { template.hideLoading(); template.showNotification(); template.back(); }) .catch((err) => { template.hideLoading(); }); // console.log("params", params); // apiEditThingModel({ // id: route.query.id, // thingModelName: template.getValues().name, // identifier: template.getValues().ident, // description: template.getValues().description, // }) // .then((res) => { // template.hideLoading(); // template.showNotification(); // template.back(); // }) // .catch((err) => { // template.hideLoading(); // }); } else { // console.log("Add", template.getValues()); const formValues = template.getValues(); if (!config.form.value.file) { proxy.$message.warning("请先上传图标文件"); template.hideLoading(); return; } const params = { iconName: template.getValues().name, typeId: modelId.value, modelIdList: template.getValues().deviceModel, // fileUrl: config.form.value.file, // ✅ 改为动态获取上传结果 fileUrl: "jichufivewife1.png", description: template.getValues().description, }; // console.log("params", params); iconStoreSubmit(params) .then((res) => { template.hideLoading(); template.showNotification(); template.back(); }) .catch((err) => { template.hideLoading(); }); } }); } </script> <style scoped lang="less"> .icon-store-form { padding: 20px; } .image-preview-container { margin-top: 20px; display: flex; align-items: center; gap: 15px; } .form-label { font-weight: 500; color: #606266; font-size: 14px; white-space: nowrap; } .image-error-slot { display: flex; align-items: center; justify-content: center; width: 100%; height: 100%; background-color: #f5f5f5; color: #999; font-size: 12px; } </style> vue 文件 Current Icon是否显示根据方法isEdit()实现;但是目前效果并没实现,vue3 应该怎么修改代码
12-13
<script lang="tsx" setup>   import { stringToBase64 } from './utils/index';   import { ref, watchEffect } from 'vue';   import { renderToString } from '@vue/server-renderer';   interface IProps {     defaultDurTime?: number; //进度条完结时间     progress?: number; //当前进度0-100     color?: object | string; //进度条颜色,传入对象格式可以定义渐变色     width?: number; //矩形宽度     height?: number; //矩形高度     radian?: number; //矩形圆角弧度     layerColor?: string; //轨道颜色     fill?: string; //填充颜色     strokeWidth?: number; //线条宽度     strokeLinecap?: string; //进度条端点(butt,round,square)   }   const props = withDefaults(defineProps<IProps>(), {     defaultDurTime: 1000, //进度条完结时间     progress: 50,     color: () => {       return { '0': '#80EDFF', '100': '#4A7DFF' };     },     width: 140,     height: 120,     radian: 20,     layerColor: '#e0e0e0',     fill: 'none',     strokeWidth: 10,     strokeLinecap: 'round',   });   const progressOffset = ref(0);   const allLen = ref(0);   const strokeBgColor = ref<string | object>('#666666');   let dataURL = ref('');   async function handleSave() {     const html = await renderToString(renderTitle());     dataURL.value = stringToBase64(html);     console.log(dataURL);   }   const renderTitle = () =>     return (       <svg         width={props.width + props.strokeWidth}         height={props.height + props.strokeWidth}         xmlns="http://www.w3.org/2000/svg"       >         {Object.prototype.toString.call(props.color) === '[object Object]' && (           <defs>             <linearGradient id="progressGradient" x1="0%" y1="0%" x2="100%" y2="0%">               {Object.keys(props.color).map((key) => (                 <stop offset={`${key}%`} stop-color={props.color[key]} key={key}></stop>               ))}             </linearGradient>           </defs>         )}         <rect           x={0.5 * props.strokeWidth}           y={0.5 * props.strokeWidth}           rx={props.radian}           ry={props.radian}           width={props.width}           height={props.height}           style={{ strokeWidth: props.strokeWidth, fill: props.fill, stroke: props.layerColor }}         />         {props.progress !== 0 && (           <rect             x={0.5 * props.strokeWidth}             y={0.5 * props.strokeWidth}             rx={props.radian}             ry={props.radian}             width={props.width}             height={props.height}             style={{               strokeDashoffset: progressOffset.value,               strokeDasharray: allLen.value,               strokeWidth: props.strokeWidth,               fill: props.fill,               stroke: strokeBgColor.value,               strokeLinecap: props.strokeLinecap,             }}           >             <animate               attributeName="stroke-dashoffset"               dur={`${props.defaultDurTime}ms`}               fill="freeze"               from={allLen.value}               to={progressOffset.value}             ></animate>           </rect>         )}       </svg>     );   };   watchEffect(() => {     allLen.value = (props.width + props.height) * 2 - props.radian * 8 + 2 * props.radian * Math.PI;     if (props.strokeLinecap !== 'butt' && props.progress !== 100 && props.progress > 95) {       progressOffset.value         allLen.value - (props.progress / 100) * allLen.value + props.strokeWidth;     } else {       progressOffset.value = allLen.value - (props.progress / 100) * allLen.value;     }     if (Object.prototype.toString.call(props.color) === '[object Object]') {       strokeBgColor.value = `url(#progressGradient)`;     } else {       strokeBgColor.value = props.color;     }     handleSave();   }); </script> 把这段代码使用vue3实现
05-14
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值