目录 vue遍历存在el-form之踩坑 初版 完善版 抽组件版 vue中el-form循环绑定 vue遍历存在el-form之踩坑 初版 template div class="message-templete-style" div class="title"短信通知模板 el-tooltip popper-class="t
目录
- vue遍历存在el-form之踩坑
- 初版
- 完善版
- 抽组件版
- vue中el-form循环绑定
vue遍历存在el-form之踩坑
初版
<template> <div class="message-templete-style"> <div class="title">短信通知模板 <el-tooltip popper-class="tooltip-style" content="请到阿里云短信平台申请短信权限" placement="bottom"> <i class="h-icon-help" :offset="85"></i> </el-tooltip></div> <el-form :model="numberForm" ref="numberForm" :rules="numberFormRule" label-width="100px" class="number-form"> <el-form-item label="测试手机号" prop="phoneNumber"> <el-input v-model="numberForm.phoneNumber"></el-input> </el-form-item> <el-form-item class="btn"> <el-button type="primary" @click="submitForm">保存</el-button> </el-form-item> </el-form> <el-tabs v-model="activeName" @tab-click="handleClick"> <el-tab-pane v-for="item in tabList" :key="item.id" :label="item.name|templateTypeFilter " :name="item.name"> <!-- <el-scrollbar wrap-class="scrollbar-wrap"> --> <el-row :gutter="12"> <el-col v-for="(itemCard, index) in item.cardList" :key="itemCard.id" :xs="8" :sm="8" :md="8" :lg="8" :xl="6"> <div class="card-wrap"> <div class="top-style"> <div class="card-title">{{ itemCard.templateName }}</div> <el-button type="text" @click="sendMessage(itemCard.templateCode)" :disabled="itemCard.templateCode ? false: true">发送</el-button> </div> <div class="content-style"> <div><h4>通知对象</h4> {{ itemCard.notifyParty | notifyPartyFilter }}</div> <div><h4>远程会议</h4> {{ itemCard.remoteMeeting | remoteMeetingFilter }}</div> <div><h4>申请模板</h4> 模板名称/内容 <el-popover width="300" trigger="hover" popper-class="detail-pop-style"> <p>模板名称 <i class="h-icon-copy" @click="copyText(itemCard.templateName, '名称')"></i></p> <div class="title">{{ itemCard.templateName }}</div> <p>模板内容<i class="h-icon-copy" @click="copyText(itemCard.templateContent, '内容')"></i></p> <!-- \n --> <div style="white-space: pre-wrap;">{{ itemCard.templateContent }}</div> <!-- --> <!-- <div v-html="itemCard.templateContent"></div> --> <i slot="reference" class="h-icon-details"></i> </el-popover> </div> <div class="code-style"><h4>模板code</h4><span class="code-width">{{ itemCard.templateCode || '' }}</span> <el-popover v-model="itemCard.visible" popper-class="code-pop-style"> <el-form :model="item" ref="codeForm" label-position="top" class="code-form"> <el-form-item label="模板code" :prop="'cardList.' + index + '.templateCodeValue'"> <el-input v-model="itemCard.templateCodeValue"></el-input> </el-form-item> <div class="btn-style"> <el-button type="primary" @click.native="confirm(index, itemCard)">确定</el-button> <el-button @click="itemCard.visible = false">取消</el-button> </div> </el-form> <i slot="reference" class="h-icon-edit" @click="openInit(itemCard)"></i> </el-popover> </div> </div> </div> </el-col> </el-row> <!-- </el-scrollbar> --> </el-tab-pane> </el-tabs> </div> </template>
<script> import rules from '@/lib/rules'; export default { filters: { templateTypeFilter: value => { switch (value) { case 'MEETING_BEFORE': return '会前通知'; case 'MEETING_DURING': return '会中通知'; case 'MEETING_AFTER': return '会后通知'; case 'NOTICE_TIMING': return '定时提醒'; case 'USER_MANAGEMENT': return '用户管理'; default: return; } }, remoteMeetingFilter: value => { switch (value) { case 'YES': return '有'; case 'NO': return '无'; default: return; } }, notifyPartyFilter: value => { switch (value) { case 'CC': return '抄送人'; case 'MEMBER': return '与会人'; case 'MEMBER_CC': return '与会人和抄送人'; case 'REGISTRANT': return '注册人'; case 'CREATOR': return '发起人'; default: return; } } }, data() { return { activeName: 'NOTICE_TIMING', // 当前激活的tab successPhoneNumber: '', // 保存成功的测试手机号 tabList: [ // { // id: 1, // name: 'hqtz', // cardList: [ // { // id: 1, // templateName: '预定会议通知1', // ,模板名称 // isSend: true, // 是否发送 // notifyParty: '发起人', // 通知对象 // remoteMeeting: true, // 是否支持远程会议 // templateContent: 'xx', // 模板内容 // templateCode: 'cc' // 模板code, // visible: false, // 是否开启弹框 // } // ] // }, { // id: 2, // name: 'hztz', // cardList: [] // }, { // id: 3, // name: 'hhtz', // cardList: [] // }, { // id: 4, // name: 'dstz', // cardList: [] // }, { // id: 5, // name: 'yhgl', // cardList: [] // } ], numberForm: { // 测试手机号 phoneNumber: '' }, numberFormRule: { phoneNumber: [rules.required('phoneNumber'), rules.phoneNumber()] } // codeFormRule: { // templateCodeValue: [ // { // required: true, // message: '请输入模板code' // // trigger: 'blur' // } // ] // } }; }, created() { this.getPhoneNumber(); this.getData(); }, methods: { // 获取测试手机号 async getPhoneNumber() { const res = await this.$get('meeting/aLiYunSmsSdk/v1/getALiYunSmsTestPhone'); this.numberForm.phoneNumber = res || ''; this.successPhoneNumber = res || ''; }, // 获取短信模板 async getData() { const res = await this.$get('meeting/template/v1/getSmsTemplateInfo'); let dataList = res || []; const newTabList = dataList.map((item, index) => { return { id: index + 1, name: item.noticePeriodName, cardList: item.noticePeriodData ? item.noticePeriodData.map(item_ => { return { id: item_.id, templateName: item_.templateName, // 模板名称 isSend: true, // 是否发送 notifyParty: item_.notifyObject, // 通知对象 remoteMeeting: item_.videoConference, // 是否支持远程会议 templateContent: item_.templateContent, // 模板内容 templateCode: item_.templateCode, // 模板code templateCodeValue: item_.templateCode, // 输入的code visible: false }; }) : [] }; }); console.log(newTabList); this.tabList = JSON.parse(JSON.stringify(newTabList)); }, // 保存测试手机号 submitForm() { this.$refs.numberForm.validate(async valid => { if (valid) { const res = await this.$get(`meeting/aLiYunSmsSdk/v1/saveALiYunSmsTestPhone/${this.numberForm.phoneNumber}`); this.successPhoneNumber = res || ''; this.$message({ message: '手机号保存成功,可用于有code码的模板进行短信测试!', type: 'success' }); } }); }, // 切换tab handleClick(tab, event) { console.log(tab, event); }, // 发送 async sendMessage(code) { if (!this.successPhoneNumber) { return this.$message({ message: '测试手机号未保存!', type: 'warning' }); } await this.$get(`meeting/sms/v1/sendSmsTest/${this.successPhoneNumber}/$[code]`); }, // 复制 copyText(text) { console.log(text);//获取input对象 //创建input标签 var input = document.createElement('textarea'); //将input的值设置为需要复制的内容 input.value = text; //添加input标签 document.body.appendChild(input); //选中input标签 input.select(); //执行复制 document.execCommand('copy'); //成功提示信息 this.$message({ message: '已复制成功!', type: 'success' }); //移除input标签 document.body.removeChild(input); }, // 开启code弹框 openInit(item) { item.templateCodeValue = item.templateCode; }, // 确认code async confirm(index, item) { console.log(index, Boolean(item.templateCodeValue)); if (!item.templateCodeValue) { return this.$message({ message: '模板code不能为空!', type: 'warning' }); } if (item.templateCodeValue) { await this.$get(`meeting/template/v1/bindingSmsTemplateCode/${item.id}/${item.templateCodeValue}`); item.templateCode = item.templateCodeValue; item.visible = false; } this.$refs.codeForm[index].focusFirstField(); } // this.$refs.codeForm[index].validate(async valid => { // if (valid) { // console.log(valid); // console.log(item); // await this.$get(`meeting/template/v1/bindingSmsTemplateCode/${item.id}/${item.templateCodeValue}`); // item.templateCode = item.templateCodeValue; // item.visible = false; // } // }); // } } }; </script>
<style lang="less"> .message-templete-style { height: 100%; // background: rgb(253, 243, 243); overflow: hidden; .title{ font-size: 16px; color:#000000; font-weight: 900; padding-bottom: 10px; .h-icon-help{ position: absolute; font-size: 26px; cursor: pointer; padding-left:2px; margin-top:-3px; } } .number-form{ height:64px; padding-top:12px; background: #F7F8F9; border-radius: 2px; display: flex; .el-form-item{ margin-bottom: 20px; } .btn .el-form-item__content{ margin-left: 10px !important; } } .el-tabs{ height: calc(100% - 94px); // background: #2080F7; padding-top:12px; // .scrollbar-wrap{ // // max-height: 700px; // } .el-tabs__item{ padding:0px 32px; span{ opacity: 0.7; font-size: 14px; } } .el-tabs__item.is-active{ color: #000000; font-weight: 900; } .el-tabs__item:hover{ color: #000000; font-weight: 900; } .el-tabs__active-bar{ background-color: #2080F7; } .el-tabs__header{ padding-bottom: 10px; } .el-tabs__content{ height:calc(100% - 51px); // background: #e8eef5; overflow: auto; // 重置滚动条位置 &::-webkit-scrollbar { width: 4px; height: 3px; background: transparent; } &::-webkit-scrollbar-thumb { background: transparent; border-radius: 4px; } &:hover::-webkit-scrollbar-thumb { background: hsla(0, 0%, 53%, 0.5); } &:hover::-webkit-scrollbar-track { background: hsla(0, 0%, 53%, 0); } .el-col{ margin-bottom: 12px; } .card-wrap{ padding: 16px 20px; background: #F7F8F9; border-radius: 2px; .top-style{ display: flex; justify-content: space-between; align-items: center; font-size: 14px; font-weight: 900; line-height: 14px; padding-bottom: 20px; .card-title{ color: #000000; } .el-button { border: 0px; height:16px; margin-top:-4px; span{ line-height: 14px; font-size: 14px; color:#2080F7; } } } .content-style{ div{ position: relative; opacity: 0.9; font-size: 14px; color: #000000; line-height: 24px; h4{ display: inline-block; opacity: 0.5; font-size: 14px; color: #000000; line-height: 24px; padding-right:16px; font-weight: normal; } .h-icon-details, .h-icon-edit{ position: absolute; font-size: 22px; cursor: pointer; padding-left:8px; } .h-icon-edit{ margin-top:-12px; } } .code-style{ display: flex; align-items: center; .code-width{ max-width:calc(100% - 104px); text-overflow: ellipsis; overflow: hidden; white-space: nowrap; line-height: 14px; font-size: 14px; font-weight: normal; } } } } } } } .detail-pop-style{ background: #FFFFFF; box-shadow: 0 0 16px 0 rgba(0,0,0,0.20), 0 16px 32px 0 rgba(0,0,0,0.12); p{ position: relative; font-weight: 900; font-size: 14px; line-height: 14px; color: #000000; padding-bottom: 8px; .h-icon-copy{ color:#1C7FFF; position: absolute; font-size: 20px; cursor: pointer; padding-left:4px; margin-top:-3px; } } .title{ padding-bottom:16px; } div{ font-size: 14px; color: rgba(0,0,0,0.50); line-height: 24px; } } .code-pop-style{ background: #FFFFFF; box-shadow: 0 0 16px 0 rgba(0,0,0,0.20), 0 16px 32px 0 rgba(0,0,0,0.12); .el-form-item__content{ margin-left:0px; } .btn-style{ float: right; } } .tooltip-style{ background: #000000; } </style>
完善版
<template> <div class="message-templete-style"> <div class="title">短信通知模板 <el-tooltip popper-class="tooltip-style" content="请到阿里云短信平台申请短信权限" placement="bottom"> <i class="h-icon-help" :offset="85"></i> </el-tooltip></div> <el-form :model="numberForm" ref="numberForm" :rules="numberFormRule" label-width="100px" class="number-form"> <el-form-item label="测试手机号" prop="phoneNumber"> <el-input v-model="numberForm.phoneNumber"></el-input> </el-form-item> <el-form-item class="btn"> <el-button type="primary" @click="submitForm">保存</el-button> </el-form-item> </el-form> <el-tabs v-model="activeName" @tab-click="handleClick"> <!-- tab头部 --> <el-tab-pane v-for="item in tabList" :key="item.key" :label="item.label|templateTypeFilter " :name="item.label"></el-tab-pane> <!-- tab内容 --> <el-row :gutter="12"> <el-col v-for="(itemCard) in templateList" :key="itemCard.id" :xs="8" :sm="8" :md="8" :lg="8" :xl="6"> <div class="card-wrap"> <div class="top-style"> <div class="card-title">{{ itemCard.templateName }}</div> <el-button type="text" @click="sendMessage(itemCard.templateCode)" :disabled="itemCard.templateCode ? false: true">发送</el-button> </div> <div class="content-style"> <div><h4>通知对象</h4> {{ itemCard.notifyParty | notifyPartyFilter }}</div> <div><h4>远程会议</h4> {{ itemCard.remoteMeeting | remoteMeetingFilter }}</div> <div><h4>申请模板</h4> 模板名称/内容 <el-popover width="300" trigger="hover" popper-class="detail-pop-style"> <p>模板名称 <i class="h-icon-copy" @click="copyText(itemCard.templateName, '名称')"></i></p> <div class="title">{{ itemCard.templateName }}</div> <p>模板内容<i class="h-icon-copy" @click="copyText(itemCard.templateContent, '内容')"></i></p> <div style="white-space: pre-wrap;">{{ itemCard.templateContent }}</div> <i slot="reference" class="h-icon-details"></i> </el-popover> </div> <div class="code-style"><h4>模板code</h4><span class="code-width">{{ itemCard.templateCode || '' }}</span> <el-popover v-model="itemCard.visible" popper-class="code-pop-style"> <el-form :model="itemCard" :ref="itemCard.id" label-position="top" class="code-form"> <el-form-item label="模板code" prop="templateCodeValue" :rules="codeFormRule.templateCodeValue"> <el-input v-model="itemCard.templateCodeValue"></el-input> </el-form-item> <div class="btn-style"> <el-button type="primary" @click="confirm(itemCard)">确定</el-button> <el-button @click="itemCard.visible = false">取消</el-button> </div> </el-form> <i slot="reference" class="h-icon-edit" @click="openInit(itemCard)"></i> </el-popover> </div> </div> </div> </el-col> </el-row> </el-tabs> </div> </template>
<script> import rules from '@/lib/rules'; export default { filters: { templateTypeFilter: value => { switch (value) { case 'MEETING_BEFORE': return '会前通知'; case 'MEETING_DURING': return '会中通知'; case 'MEETING_AFTER': return '会后通知'; case 'NOTICE_TIMING': return '定时提醒'; case 'USER_MANAGEMENT': return '用户管理'; default: return; } }, remoteMeetingFilter: value => { switch (value) { case 'YES': return '有'; case 'NO': return '无'; default: return; } }, notifyPartyFilter: value => { switch (value) { case 'CC': return '抄送人'; case 'MEMBER': return '与会人'; case 'MEMBER_CC': return '与会人和抄送人'; case 'REGISTRANT': return '注册人'; case 'CREATOR': return '发起人'; default: return; } } }, data() { return { activeName: 'NOTICE_TIMING', // 当前激活的tab successPhoneNumber: '', // 保存成功的测试手机号 tabList: [ // 获取的所有数据 重组数据结构如下: // { // key: 1, // label: 'MEETING_AFTER', // contentList: [] // }, // { // key: 2, // label: 'MEETING_BEFORE', // contentList: [] // }, // { // key: 3, // label: 'MEETING_DURING', // contentList: [] // }, // { // key: 4, // label: 'NOTICE_TIMING', // contentList: [] // }, // { // key: 5, // label: 'USER_MANAGEMENT', // contentList: [] // } ], templateList: [], // 要渲染的模板列表 numberForm: { // 测试手机号 phoneNumber: '' }, numberFormRule: { // 测试手机号校验 phoneNumber: [rules.required('phoneNumber'), rules.phoneNumber()] }, codeFormRule: { // 模板code校验 templateCodeValue: [ // rules.required('templateCodeValue') { required: true, message: '请输入模板code' // trigger: 'blur' } ] } }; }, created() { this.getPhoneNumber(); this.getData(); }, methods: { // 获取测试手机号 async getPhoneNumber() { const res = await this.$get('meeting/aLiYunSmsSdk/v1/getALiYunSmsTestPhone'); this.numberForm.phoneNumber = res || ''; this.successPhoneNumber = res || ''; }, // 获取短信模板 async getData() { const res = await this.$get('meeting/template/v1/getSmsTemplateInfo'); let dataList = res || []; const newTabList = dataList.map((item, index) => { return { key: index + 1, label: item.noticePeriodName, contentList: item.noticePeriodData ? item.noticePeriodData.map(item_ => { return { id: item_.id, templateName: item_.templateName, // 模板名称 isSend: true, // 是否发送 notifyParty: item_.notifyObject, // 通知对象 remoteMeeting: item_.videoConference, // 是否支持远程会议 templateContent: item_.templateContent, // 模板内容 templateCode: item_.templateCode, // 模板code templateCodeValue: item_.templateCode, // 双向绑定的code visible: false }; }) : [] }; }); this.tabList = JSON.parse(JSON.stringify(newTabList)); this.templateList = newTabList[0] ? JSON.parse(JSON.stringify(newTabList))[0].contentList : []; }, // 保存测试手机号 submitForm() { this.$refs.numberForm.validate(async valid => { if (valid) { const res = await this.$get(`meeting/aLiYunSmsSdk/v1/saveALiYunSmsTestPhone/${this.numberForm.phoneNumber}`); this.successPhoneNumber = res || ''; this.$message({ message: '手机号保存成功,可用于有code码的模板进行短信测试!', type: 'success' }); } }); }, // 切换tab (按理此处可以通过接口获取,因为数据少,所以后端一次性返回,前端自行处理) handleClick(tab) { const newArr = JSON.parse(JSON.stringify(this.tabList)); let newTemplateList = JSON.parse(JSON.stringify(this.templateList)); for (let i = 0; i < newArr.length; i++) { if (newArr[i].label === tab.name) { newTemplateList = newArr[i].contentList; } } this.templateList = newTemplateList; }, // 发送 async sendMessage(code) { if (!this.successPhoneNumber) { return this.$message({ message: '测试手机号未保存!', type: 'warning' }); } await this.$get(`meeting/sms/v1/sendSmsTest/${this.successPhoneNumber}/$[code]`); }, // 复制 copyText(text) { console.log(text);//获取input对象 //创建input标签 var input = document.createElement('textarea'); //将input的值设置为需要复制的内容 input.value = text; //添加input标签 document.body.appendChild(input); //选中input标签 input.select(); //执行复制 document.execCommand('copy'); //成功提示信息 this.$message({ message: '已复制成功!', type: 'success' }); //移除input标签 document.body.removeChild(input); }, // 开启code弹框 openInit(item) { item.templateCodeValue = item.templateCode; }, // 确认code async confirm(item) { this.$refs[item.id][0].validate(async valid => { if (valid) { await this.$get(`meeting/template/v1/bindingSmsTemplateCode/${item.id}/${item.templateCodeValue}`); item.templateCode = item.templateCodeValue; item.visible = false; } }); } } }; </script>
<style lang="less"> .message-templete-style { height: 100%; // background: rgb(253, 243, 243); overflow: hidden; .title{ font-size: 16px; color:#000000; font-weight: 900; padding-bottom: 10px; .h-icon-help{ position: absolute; font-size: 26px; cursor: pointer; padding-left:2px; margin-top:-3px; } } .number-form{ height:64px; padding-top:12px; background: #F7F8F9; border-radius: 2px; display: flex; .el-form-item{ margin-bottom: 20px; } .btn .el-form-item__content{ margin-left: 10px !important; } } .el-tabs{ height: calc(100% - 94px); // background: #2080F7; padding-top:12px; .el-tabs__item{ padding:0px 32px; span{ opacity: 0.7; font-size: 14px; } } .el-tabs__item.is-active{ color: #000000; font-weight: 900; } .el-tabs__item:hover{ color: #000000; font-weight: 900; } .el-tabs__active-bar{ background-color: #2080F7; } .el-tabs__header{ padding-bottom: 10px; } .el-tabs__content{ height:calc(100% - 51px); // background: #e8eef5; overflow: auto; // 重置滚动条位置 &::-webkit-scrollbar { width: 4px; height: 3px; background: transparent; } &::-webkit-scrollbar-thumb { background: transparent; border-radius: 4px; } &:hover::-webkit-scrollbar-thumb { background: hsla(0, 0%, 53%, 0.5); } &:hover::-webkit-scrollbar-track { background: hsla(0, 0%, 53%, 0); } .el-col{ margin-bottom: 12px; } .card-wrap{ padding: 16px 20px; background: #F7F8F9; border-radius: 2px; .top-style{ display: flex; justify-content: space-between; align-items: center; font-size: 14px; font-weight: 900; line-height: 14px; padding-bottom: 20px; .card-title{ color: #000000; } .el-button { border: 0px; height:16px; margin-top:-4px; span{ line-height: 14px; font-size: 14px; color:#2080F7; } } } .content-style{ div{ position: relative; opacity: 0.9; font-size: 14px; color: #000000; line-height: 24px; h4{ display: inline-block; opacity: 0.5; font-size: 14px; color: #000000; line-height: 24px; padding-right:16px; font-weight: normal; } .h-icon-details, .h-icon-edit{ position: absolute; font-size: 22px; cursor: pointer; padding-left:8px; } .h-icon-edit{ margin-top:-12px; } } .code-style{ display: flex; align-items: center; .code-width{ max-width:calc(100% - 104px); text-overflow: ellipsis; overflow: hidden; white-space: nowrap; line-height: 14px; font-size: 14px; font-weight: normal; } } } } } } } .detail-pop-style{ background: #FFFFFF; box-shadow: 0 0 16px 0 rgba(0,0,0,0.20), 0 16px 32px 0 rgba(0,0,0,0.12); p{ position: relative; font-weight: 900; font-size: 14px; line-height: 14px; color: #000000; padding-bottom: 8px; .h-icon-copy{ color:#1C7FFF; position: absolute; font-size: 20px; cursor: pointer; padding-left:4px; margin-top:-3px; } } .title{ padding-bottom:16px; } div{ font-size: 14px; color: rgba(0,0,0,0.50); line-height: 24px; } } .code-pop-style{ background: #FFFFFF; box-shadow: 0 0 16px 0 rgba(0,0,0,0.20), 0 16px 32px 0 rgba(0,0,0,0.12); .el-form-item__content{ margin-left:0px; } .btn-style{ float: right; } } .tooltip-style{ background: #000000; } </style>
抽组件版
父组件: <template> <div class="message-templete-style"> <div class="title">短信通知模板 <el-tooltip popper-class="tooltip-style" content="请到阿里云短信平台申请短信权限" placement="bottom"> <i class="h-icon-help" :offset="85"></i> </el-tooltip></div> <el-form :model="numberForm" ref="numberForm" :rules="numberFormRule" label-width="100px" class="number-form"> <el-form-item label="测试手机号" prop="phoneNumber"> <el-input v-model="numberForm.phoneNumber"></el-input> </el-form-item> <el-form-item class="btn"> <el-button type="primary" @click="submitForm">保存</el-button> </el-form-item> </el-form> <el-tabs v-model="activeName" @tab-click="handleClick"> <!-- tab头部 --> <el-tab-pane v-for="item in tabList" :key="item.key" :label="item.label|templateTypeFilter " :name="item.label"></el-tab-pane> <!-- tab内容 --> <el-row :gutter="12"> <el-col v-for="(itemCard) in templateList" :key="itemCard.id" :xs="8" :sm="8" :md="8" :lg="8" :xl="6"> <template-card :success-phone-number="successPhoneNumber" :item-card="itemCard"></template-card> <!-- <div class="card-wrap"> <div class="top-style"> <div class="card-title">{{ itemCard.templateName }}</div> <el-button type="text" @click="sendMessage(itemCard.templateCode)" :disabled="itemCard.templateCode ? false: true">发送</el-button> </div> <div class="content-style"> <div><h4>通知对象</h4> {{ itemCard.notifyParty | notifyPartyFilter }}</div> <div><h4>远程会议</h4> {{ itemCard.remoteMeeting | remoteMeetingFilter }}</div> <div><h4>申请模板</h4> 模板名称/内容 <el-popover width="300" trigger="hover" popper-class="detail-pop-style"> <p>模板名称 <i class="h-icon-copy" @click="copyText(itemCard.templateName, '名称')"></i></p> <div class="title">{{ itemCard.templateName }}</div> <p>模板内容<i class="h-icon-copy" @click="copyText(itemCard.templateContent, '内容')"></i></p> <div style="white-space: pre-wrap;">{{ itemCard.templateContent }}</div> <i slot="reference" class="h-icon-details"></i> </el-popover> </div> <div class="code-style"><h4>模板code</h4><span class="code-width">{{ itemCard.templateCode || '' }}</span> <el-popover v-model="itemCard.visible" popper-class="code-pop-style"> <el-form :model="itemCard" :ref="itemCard.id" label-position="top" class="code-form"> <el-form-item label="模板code" prop="templateCodeValue" :rules="codeFormRule.templateCodeValue"> <el-input v-model="itemCard.templateCodeValue"></el-input> </el-form-item> <div class="btn-style"> <el-button type="primary" @click="confirm(itemCard)">确定</el-button> <el-button @click="itemCard.visible = false">取消</el-button> </div> </el-form> <i slot="reference" class="h-icon-edit" @click="openInit(itemCard)"></i> </el-popover> </div> </div> </div> --> </el-col> </el-row> </el-tabs> </div> </template>
<script> import rules from '@/lib/rules'; import templateCard from '@/components/view/SettingManage/templateCard.vue'; export default { components: { templateCard }, filters: { templateTypeFilter: value => { switch (value) { case 'MEETING_BEFORE': return '会前通知'; case 'MEETING_DURING': return '会中通知'; case 'MEETING_AFTER': return '会后通知'; case 'NOTICE_TIMING': return '定时提醒'; case 'USER_MANAGEMENT': return '用户管理'; default: return; } } }, data() { return { activeName: 'NOTICE_TIMING', // 当前激活的tab successPhoneNumber: '', // 保存成功的测试手机号 tabList: [ // 获取的所有数据 重组数据结构如下: // { // key: 1, // label: 'MEETING_AFTER', // contentList: [] // }, // { // key: 2, // label: 'MEETING_BEFORE', // contentList: [] // }, // { // key: 3, // label: 'MEETING_DURING', // contentList: [] // }, // { // key: 4, // label: 'NOTICE_TIMING', // contentList: [] // }, // { // key: 5, // label: 'USER_MANAGEMENT', // contentList: [] // } ], templateList: [], // 要渲染的模板列表 numberForm: { // 测试手机号 phoneNumber: '' }, numberFormRule: { // 测试手机号校验 phoneNumber: [rules.required('phoneNumber'), rules.phoneNumber()] }, codeFormRule: { // 模板code校验 templateCodeValue: [ // rules.required('templateCodeValue') { required: true, message: '请输入模板code' // trigger: 'blur' } ] } }; }, created() { this.getPhoneNumber(); this.getData(); }, methods: { // 获取测试手机号 async getPhoneNumber() { const res = await this.$get('meeting/aLiYunSmsSdk/v1/getALiYunSmsTestPhone'); this.numberForm.phoneNumber = res || ''; this.successPhoneNumber = res || ''; }, // 获取短信模板 async getData() { const res = await this.$get('meeting/template/v1/getSmsTemplateInfo'); let dataList = res || []; const newTabList = dataList.map((item, index) => { return { key: index + 1, label: item.noticePeriodName, contentList: item.noticePeriodData ? item.noticePeriodData.map(item_ => { return { id: item_.id, templateName: item_.templateName, // 模板名称 isSend: true, // 是否发送 notifyParty: item_.notifyObject, // 通知对象 remoteMeeting: item_.videoConference, // 是否支持远程会议 templateContent: item_.templateContent, // 模板内容 templateCode: item_.templateCode, // 模板code templateCodeValue: item_.templateCode, // 双向绑定的code visible: false }; }) : [] }; }); this.tabList = JSON.parse(JSON.stringify(newTabList)); this.templateList = newTabList[0] ? JSON.parse(JSON.stringify(newTabList))[0].contentList : []; }, // 保存测试手机号 submitForm() { this.$refs.numberForm.validate(async valid => { if (valid) { const res = await this.$get(`meeting/aLiYunSmsSdk/v1/saveALiYunSmsTestPhone/${this.numberForm.phoneNumber}`); this.successPhoneNumber = res || ''; this.$message({ message: '手机号保存成功,可用于有code码的模板进行短信测试!', type: 'success' }); } }); }, // 切换tab (按理此处可以通过接口获取,因为数据少,所以后端一次性返回,前端自行处理) handleClick(tab) { const newArr = JSON.parse(JSON.stringify(this.tabList)); let newTemplateList = JSON.parse(JSON.stringify(this.templateList)); for (let i = 0; i < newArr.length; i++) { if (newArr[i].label === tab.name) { newTemplateList = newArr[i].contentList; } } this.templateList = newTemplateList; } } }; </script>
<style lang="less" scoped> .message-templete-style { height: 100%; // background: rgb(253, 243, 243); overflow: hidden; .title{ font-size: 16px; color:#000000; font-weight: 900; padding-bottom: 10px; .h-icon-help{ position: absolute; font-size: 26px; cursor: pointer; padding-left:2px; margin-top:-3px; } } .number-form{ height:64px; padding-top:12px; background: #F7F8F9; border-radius: 2px; display: flex; .el-form-item{ margin-bottom: 20px; } .btn .el-form-item__content{ margin-left: 10px !important; } } .el-tabs{ height: calc(100% - 94px); // background: #2080F7; padding-top:12px; .el-tabs__item{ padding:0px 32px; span{ opacity: 0.7; font-size: 14px; } } .el-tabs__item.is-active{ color: #000000; font-weight: 900; } .el-tabs__item:hover{ color: #000000; font-weight: 900; } .el-tabs__active-bar{ background-color: #2080F7; } .el-tabs__header{ padding-bottom: 10px; } .el-tabs__content{ height:calc(100% - 51px); // background: #e8eef5; overflow: auto; // 重置滚动条位置 &::-webkit-scrollbar { width: 4px; height: 3px; background: transparent; } &::-webkit-scrollbar-thumb { background: transparent; border-radius: 4px; } &:hover::-webkit-scrollbar-thumb { background: hsla(0, 0%, 53%, 0.5); } &:hover::-webkit-scrollbar-track { background: hsla(0, 0%, 53%, 0); } .el-col{ margin-bottom: 12px; } } } } .tooltip-style{ background: #000000; } </style>
```javascript 子组件: <template> <div class="card-wrap"> <div class="top-style"> <div class="card-title">{{ itemCard.templateName }}</div> <el-button type="text" @click="sendMessage(itemCard.templateCode)" :disabled="itemCard.templateCode ? false: true">发送</el-button> </div> <div class="content-style"> <div><h4>通知对象</h4> {{ itemCard.notifyParty | notifyPartyFilter }}</div> <div><h4>远程会议</h4> {{ itemCard.remoteMeeting | remoteMeetingFilter }}</div> <div><h4>申请模板</h4> 模板名称/内容 <el-popover width="300" trigger="hover" popper-class="detail-pop-style"> <p>模板名称 <i class="h-icon-copy" @click="copyText(itemCard.templateName, '名称')"></i></p> <div class="title">{{ itemCard.templateName }}</div> <p>模板内容<i class="h-icon-copy" @click="copyText(itemCard.templateContent, '内容')"></i></p> <div style="white-space: pre-wrap;">{{ itemCard.templateContent }}</div> <i slot="reference" class="h-icon-details"></i> </el-popover> </div> <div class="code-style"><h4>模板code</h4><span class="code-width">{{ itemCard.templateCode || '' }}</span> <el-popover v-model="itemCard.visible" popper-class="code-pop-style"> <el-form :model="itemCard" :ref="itemCard.id" label-position="top" class="code-form"> <el-form-item label="模板code" prop="templateCodeValue" :rules="codeFormRule.templateCodeValue"> <el-input v-model="itemCard.templateCodeValue"></el-input> </el-form-item> <div class="btn-style"> <el-button type="primary" @click="confirm(itemCard)">确定</el-button> <el-button @click="itemCard.visible = false">取消</el-button> </div> </el-form> <i slot="reference" class="h-icon-edit" @click="openInit(itemCard)"></i> </el-popover> </div> </div> </div> </template>
<script> export default { filters: { remoteMeetingFilter: value => { switch (value) { case 'YES': return '有'; case 'NO': return '无'; default: return; } }, notifyPartyFilter: value => { switch (value) { case 'CC': return '抄送人'; case 'MEMBER': return '与会人'; case 'MEMBER_CC': return '与会人和抄送人'; case 'REGISTRANT': return '注册人'; case 'CREATOR': return '发起人'; default: return; } } }, props: { successPhoneNumber: { type: String, default: '' }, itemCard: { type: Object, default: () => ({}) } }, data() { return { codeFormRule: { // 模板code校验 templateCodeValue: [ // rules.required('templateCodeValue') { required: true, message: '请输入模板code' // trigger: 'blur' } ] } }; }, methods: { // 发送 async sendMessage(code) { if (!this.successPhoneNumber) { return this.$message({ message: '测试手机号未保存!', type: 'warning' }); } await this.$get(`meeting/sms/v1/sendSmsTest/${this.successPhoneNumber}/$[code]`); }, // 复制 copyText(text) { console.log(text);//获取input对象 //创建input标签 var input = document.createElement('textarea'); //将input的值设置为需要复制的内容 input.value = text; //添加input标签 document.body.appendChild(input); //选中input标签 input.select(); //执行复制 document.execCommand('copy'); //成功提示信息 this.$message({ message: '已复制成功!', type: 'success' }); //移除input标签 document.body.removeChild(input); }, // 开启code弹框 openInit(item) { item.templateCodeValue = item.templateCode; }, // 确认code confirm(item) { this.$refs[item.id].validate(async valid => { if (valid) { await this.$get(`meeting/template/v1/bindingSmsTemplateCode/${item.id}/${item.templateCodeValue}`); item.templateCode = item.templateCodeValue; item.visible = false; } }); } } }; </script>
<style lang='less' scoped> .card-wrap{ padding: 16px 20px; background: #F7F8F9; border-radius: 2px; .top-style{ display: flex; justify-content: space-between; align-items: center; font-size: 14px; font-weight: 900; line-height: 14px; padding-bottom: 20px; .card-title{ color: #000000; } /deep/.el-button { border: 0px; height:16px; margin-top:-4px; span{ line-height: 14px; font-size: 14px; color:#2080F7; } } } .content-style{ div{ position: relative; opacity: 0.9; font-size: 14px; color: #000000; line-height: 24px; h4{ display: inline-block; opacity: 0.5; font-size: 14px; color: #000000; line-height: 24px; padding-right:16px; font-weight: normal; } .h-icon-details, .h-icon-edit{ position: absolute; font-size: 22px; cursor: pointer; padding-left:8px; } .h-icon-edit{ margin-top:-12px; } } .code-style{ display: flex; align-items: center; .code-width{ max-width:calc(100% - 104px); text-overflow: ellipsis; overflow: hidden; white-space: nowrap; line-height: 14px; font-size: 14px; font-weight: normal; } } } } .detail-pop-style{ background: #FFFFFF; box-shadow: 0 0 16px 0 rgba(0,0,0,0.20), 0 16px 32px 0 rgba(0,0,0,0.12); p{ position: relative; font-weight: 900; font-size: 14px; line-height: 14px; color: #000000; padding-bottom: 8px; .h-icon-copy{ color:#1C7FFF; position: absolute; font-size: 20px; cursor: pointer; padding-left:4px; margin-top:-3px; } } .title{ padding-bottom:16px; } div{ font-size: 14px; color: rgba(0,0,0,0.50); line-height: 24px; } } .code-pop-style{ background: #FFFFFF; box-shadow: 0 0 16px 0 rgba(0,0,0,0.20), 0 16px 32px 0 rgba(0,0,0,0.12); .code-form{ /deep/ .el-form-item__content{ margin-left:0px; } .btn-style{ float: right; } } } </style>
vue中el-form循环绑定
在我们开发过程中,有时会遇到el-form循环绑定校验,并且后台返回的是动态表单list的形式,并且动态绑定是否必填
<el-form ref="addForm" :model="submitForm" //绑定的表单对象 label-width="125px" :rules="rules" //绑定的校验规则 > <el-form-item v-for="(item,index) in formArr" :key="index" :label="item.fieldName + ' : ' " :required="item.isRequired==1?true:false" :prop="item.fieldIdentify"> <el-input v-if="item.fieldIdentify=='AAA'" style="width:100%;color:#DBDBDD;" type="text" v-model="submitForm.AAA"></el-input> <el-input v-if="item.fieldIdentify=='BBB'" style="width:100%;color:#DBDBDD;" type="text" v-model="submitForm.BBB"></el-input> <el-input v-if="item.fieldIdentify=='CCC'" style="width:100%;color:#DBDBDD;" type="text" v-model="submitForm.CCC"></el-input> <el-form-item class="textarea form_textarea" v-if="item.fieldIdentify=='DDD'" :prop="item.fieldIdentify"> <el-input style="width:650px;" type="textarea" v-model="submitForm.DDD"></el-input> </el-form-item> </el-form-item> </el-form> <script> export default { data(){ return{ submitForm:{ AAA:'', BBB:'', CCC:'', DDD:'' }, //formArr数据类似 formArr:[ { fieldIdentify: "xxx", fieldName: "xxx", fieldValue: "xxx", isRequired: 1 }, { fieldIdentify: "xxx", fieldName: "xxx", fieldValue: "xxx", isRequired: 1 }, { fieldIdentify: "xxx", fieldName: "xxx", fieldValue: "xxx", isRequired: 1 } ], //注意在el-form-item的:prop值要和rules里面的值相同 rules:{ AAA:[{ required: true, message: "AAA不能为空", trigger: ["blur","change"] }], BBB:[{ required: true, message: "BBB不能为空", trigger: ["blur","change"] }], CCC:[{ required: true, message: "CCC不能为空", trigger: ["blur","change"] }], DDD:[{ required: true, message: "CCC不能为空", trigger: ["blur","change"] }] } } } } </script>
以上为个人经验,希望能给大家一个参考,也希望大家多多支持自由互联。