目录
- 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 ; | |
} | |
} | |
.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 ; | |
} | |
} | |
.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 ; | |
} | |
} | |
.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> |