// 申请模板
<template>
<div class="app-container">
<el-row type="flex" :gutter="20" justify="space-between">
<!-- 左侧表单 -->
<el-col :span="10">
<div class="title">
模板内容
</div>
<el-form ref="ruleFormRef" :model="form" label-width="120px" :rules="rules">
<el-form-item label="模板标题" prop="title">
<el-input v-model="form.title" />
<p>展示为消息推送的标题,请您谨慎填写,建议标题以“通知”
或“提醒”作为结尾</p>
</el-form-item>
<el-form-item label="模板内容" prop="preContent">
<div class="dis-row">
<el-col :span="24">
<el-input id="inputRef1" ref="inputRef3" type="textarea" placeholder="请填写模板内容" @blur="blur"
@keydown.delete.native="del" v-model="form.preContent" />
</el-col>
<el-col>
<span class="add-btn-border" @click="add1" style="margin-left: 20px;">插入数值</span>
</el-col>
</div>
<p>可插入多个数值,如不需要模板开头可不填写此项</p>
</el-form-item>
<!-- 动态创建的数值元素 -->
<el-form-item v-for="(item, i) in form.templateItemReqList" :key="i"
:prop="`templateItemReqList[${i}].itemContent`" :rules="[{
required: true,
message: '',
trigger: 'blur'
},
{ required: true, trigger: 'blur', validator:(rule, value, callback)=> validatePlaceholder(rule, value,callback,item)}
]">
<el-col :span="6">
<el-input v-model="item.itemContent" placeholder="请填写数值名称" />
</el-col>
<el-col :span="18">
{{ item.placeholder }} :
<span class="add-btn-border" @click="addBodyNums(item)" style="margin-left: 20px;">插入数值</span>
<span class="del-btn-border" @click="delBodyItem(i)" style="margin-left: 20px;">删除数值</span>
</el-col>
</el-form-item>
<el-form-item>
<p @click="addBodyItem" class="add-btn">增加数值</p>
</el-form-item>
<el-form-item prop="postContent">
<div class="dis-row">
<el-col :span="24">
<el-input id="inputRef3" ref="inputRef3" type="textarea" placeholder="请填写模板结尾" @blur="blur"
@keydown.delete.native="delFootNums" v-model="form.postContent" />
</el-col>
<el-col>
<span class="add-btn-border" @click="addFootNums" style="margin-left: 20px;">插入数值</span>
</el-col>
</div>
<p>可插入多个数值,如不需要模板开头可不填写此项</p>
</el-form-item>
<el-form-item label="消息链接" prop="needUrl">
<el-radio-group v-model="form.needUrl">
<el-radio :label="1">
需要 <span v-show="form.needUrl == 1" style="color: #aaa;">{data1|链接}</span>
</el-radio>
<el-radio :label="0">
不需要
</el-radio>
</el-radio-group>
<p>
* 如果您不需要消息链接,则推送消息时不展示“查看详情”。 如果您设置了需要消息链接且提供了链接参数。则消息推送时展示“查看详情”。
</p>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSubmit(ruleFormRef)">提交申请</el-button>
</el-form-item>
</el-form>
</el-col>
<!-- 右侧展示 -->
<el-col :span="10">
<div class="messageExample">
<div class="title">
消息示例
</div>
<div class="messageExample-contentBox">
<div class="messageExample-contentBox-title">
{{ form.title }}
</div>
<div class="messageExample-contentBox-preContent">
{{ form.preContent }}
</div>
<div class="messageExample-contentBox-item" v-for="(item, i) in form.templateItemReqList" :key="i">
<div v-if="item.itemContent && item.placeholder">
{{ item.itemContent }}:<span style="
color: #aaa;
">
{{ item.placeholder }}
</span>
</div>
</div>
<div class="messageExample-contentBox-postContent">
{{ form.postContent }}
</div>
<div v-show="form.needUrl == 1" class="messageExample-contentBox-seeDetail">
<span>查看详情</span> <span>></span>
</div>
</div>
</div>
</el-col>
</el-row>
<diaLog @diaLogConfirm="diaLogConfirm" :dialogInfo="dialogInfo">
<template #dialogMain>
<div>
<div v-for="(value, key, index) in form">
<div class="item" v-if="form2Chinese.hasOwnProperty(key)">
<span class="item-key">
{{ form2Chinese[key] }}
</span>
<span class="item-value">
<span v-if="key == 'needUrl'">
{data1|链接}
</span>
<span v-else-if="key == 'templateItemReqList'" class="templateItemList">
<span v-for="(item2, i2) in value" :key="i2" class="templateItemList-item">
{{ item2.itemContent }}<span style="margin-right: 10px;">:</span> {{
item2.placeholder
}}
</span>
</span>
<span v-else> {{ value }}</span>
</span>
</div>
</div>
</div>
</template>
</diaLog>
</div>
</template>
<script setup name="templateApply">
import diaLog from './components/diaLog.vue';
import { h, nextTick, reactive, ref, toRefs, } from 'vue'
import { ElMessageBox, ElMessage } from 'element-plus'
import * as messageTemplate from '@/api/messageTemplate'
const inputRef3 = ref(null)
// do not use same name with ref
const data = reactive({
form: {
title: '',//模板标题
preContent: '',//模板内容
templateItemReqList: [
{
itemContent: "",//内容(数值名称)
placeholder: "",//占位符(数值)
},
],
postContent: "",//模板结尾
needUrl: "",//是否需要链接
status: 1,//状态 (0 保存草稿 1提交审核 2审核通过)
},
// 对对象中属性进行定义
form2Chinese: {
id: "模板编号",
title: "模板标题",
preContent: "模板内容",
templateItemReqList: "",
postContent: "",
needUrl: "消息链接",
},
tabActiveIndex: 0, //增加数值的tab高亮项
headNums: 0, //模板内容中的数值数量
bodyNums: 0, //模板身体中的数值数量
footNums: 0, //模板结尾中的数值数量
focusIndex: 0, // 模板内容中的光标位置
// add2的插入值
templateItemReqList: [
{
itemContent: "",//内容(数值名称)
placeholder: "",//占位符(数值)
},
],
insertTxt2: ""
})
const { form, form2Chinese } = data
const ruleFormRef = ref()
const rules = reactive({
title: [
{ required: true, message: '', trigger: 'blur' },
],
preContent: [
{ required: true, message: '', trigger: 'blur' },
]
,
postContent: [
{ required: true, message: '', trigger: 'blur' },
],
needUrl: [
{ required: true, message: '请选择是否需要消息链接', trigger: 'blur' },
],
})
const validatePlaceholder = (rule, value, callback, item) => {
if (value) {
console.log('placeholder:',{item});
if (!item.placeholder) {
callback(new Error('请插入该项数值'))
} else {
callback()
}
} else {
callback()
}
}
const dialogInfo = reactive({
title: "模板预览",
show: false,
cancelText: "取消",
confirmText: "确认提交",
})
const onSubmit = async (formEl) => {
console.log({ formEl });
if (!formEl) return
await formEl.validate((valid, fields) => {
if (valid) {
console.log('submit!', form)
dialogInfo.show = true
} else {
console.log('error submit!', fields)
}
})
}
// diaLog从子组件接收的数据
const diaLogConfirm = async (value) => {
console.log({ value });
const res = await messageTemplate.addOrUpdateTemplate(form)
console.log({ res });
if (res.code == 200) {
dialogInfo.show = false
ElMessage({
message: '提交成功',
type: 'success',
})
}
}
const blur = (e) => {
console.log('光标位置:', e.srcElement.selectionStart);
data.focusIndex = e.srcElement.selectionStart
}
// head 插入模板内容的数值
const add1 = () => {
console.log('位置:', inputRef3.value.ref.selectionStart);
// 聚焦
inputRef3.value.focus()
let items = [
'时间',
'金额',
'数字',
'文本'
]
ElMessageBox({
title: '请选择数据类型',
message: () => h('p', null,
items.map((item, i) => {
return h('div', {
style: {
color: data.tabActiveIndex === i ? '#FFF' : 'teal',
backgroundColor: data.tabActiveIndex === i ? 'teal' : '#FFF',
border: '1px solid teal',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
padding: '8px',
marginBottom: '10px'
},
onClick: (e) => {
console.log({ e });
data.tabActiveIndex = i
}
}, item)
})
),
}).then(() => {
data.headNums++
// 需要插入的数值
let insertTxt = `{head.data${data.headNums}|${items[data.tabActiveIndex]}}`
form.preContent = form.preContent.slice(0, data.focusIndex) + insertTxt + form.preContent.slice(data.focusIndex)
// 将光标定到插入后的位置
nextTick(() => {
inputRef3.value.focus()
inputRef3.value.ref.selectionStart = data.focusIndex + insertTxt.length
inputRef3.value.ref.selectionEnd = data.focusIndex + insertTxt.length
})
})
}
// 模板内容的删除
const del = (e) => {
console.log({ e });
console.log({ form });
let content = form.preContent
if (!content) return//没有内容就不用进行后面操作
let start = e.target.selectionStart//光标起始位置
let end = e.target.selectionEnd//光标起始位置
// 拿到整个需要删除的变量
if (start == end) {
// 获取光标左侧最近的"{"位置
const leftIndex = content.substr(0, start).lastIndexOf("{")
// 判断光标左侧是否有"{" 来判断是否有插入的数值变量
if (leftIndex != -1) {
// 如果拿到的话 获取光标右侧最近的"}"
const rightIndex = leftIndex + content.substr(leftIndex).indexOf("}")
console.log(start, end, leftIndex, rightIndex);
// 判断光标是否在需要删除的变量中
if (start > leftIndex && start <= rightIndex + 1) {
console.log('截取的字符串:', { leftIndex }, { rightIndex }, content.substr(leftIndex, rightIndex + 1));
e.target.setSelectionRange(leftIndex, rightIndex + 1)
e.preventDefault()
}
}
}
}
//body 插入数值条数
const addBodyItem = () => {
console.log('add2');
nextTick(() => {
form.templateItemReqList = [...form.templateItemReqList, {
itemContent: "",
placeholder: "",
}]
})
}
const addBodyNums = (item) => {
let items = [
'时间',
'金额',
'数字',
'文本'
]
ElMessageBox({
title: '请选择数据类型',
message: () => h('p', null,
items.map((item, i) => {
return h('div', {
style: {
color: data.tabActiveIndex === i ? '#FFF' : 'teal',
backgroundColor: data.tabActiveIndex === i ? 'teal' : '#FFF',
border: '1px solid teal',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
padding: '8px',
marginBottom: '10px'
},
onClick: (e) => {
console.log({ e });
data.tabActiveIndex = i
}
}, item)
})
),
}).then(() => {
data.bodyNums++
// 需要插入的数值
let insertTxt = `{body.data${data.bodyNums}|${items[data.tabActiveIndex]}}`
item.placeholder = insertTxt
})
}
// 删除数值
const delBodyItem = (i) => {
if (form.templateItemReqList.length <= 1) {
ElMessage('已经是最后一个了')
return
}
form.templateItemReqList = form.templateItemReqList.filter((item, index) => {
return i != index
})
form.templateItemReqList.forEach((item, i) => {
item.placeholder = `{data${i + 1}}`
})
}
// 模板结尾的新增
const addFootNums = () => {
console.log('位置:', inputRef3.value.ref.selectionStart);
// 聚焦
inputRef3.value.focus()
let items = [
'时间',
'金额',
'数字',
'文本'
]
ElMessageBox({
title: '请选择数据类型',
message: () => h('p', null,
items.map((item, i) => {
return h('div', {
style: {
color: data.tabActiveIndex === i ? '#FFF' : 'teal',
backgroundColor: data.tabActiveIndex === i ? 'teal' : '#FFF',
border: '1px solid teal',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
padding: '8px',
marginBottom: '10px'
},
onClick: (e) => {
console.log({ e });
data.tabActiveIndex = i
}
}, item)
})
),
}).then(() => {
data.footNums++
// 需要插入的数值
let insertTxt = `{foot.data${data.footNums}|${items[data.tabActiveIndex]}}`
form.postContent = form.postContent.slice(0, data.focusIndex) + insertTxt + form.postContent.slice(data.focusIndex)
// 将光标定到插入后的位置
nextTick(() => {
inputRef3.value.focus()
inputRef3.value.ref.selectionStart = data.focusIndex + insertTxt.length
inputRef3.value.ref.selectionEnd = data.focusIndex + insertTxt.length
})
})
}
// 模板结尾的删除
const delFootNums = (e) => {
console.log({ e });
console.log({ form });
let content = form.postContent
if (!content) return//没有内容就不用进行后面操作
let start = e.target.selectionStart//光标起始位置
let end = e.target.selectionEnd//光标起始位置
// 拿到整个需要删除的变量
if (start == end) {
// 获取光标左侧最近的"{"位置
const leftIndex = content.substr(0, start).lastIndexOf("{")
// 判断光标左侧是否有"{" 来判断是否有插入的数值变量
if (leftIndex != -1) {
// 如果拿到的话 获取光标右侧最近的"}"
const rightIndex = leftIndex + content.substr(leftIndex).indexOf("}")
console.log(start, end, leftIndex, rightIndex);
// 判断光标是否在需要删除的变量中
if (start > leftIndex && start <= rightIndex + 1) {
console.log('截取的字符串:', { leftIndex }, { rightIndex }, content.substr(leftIndex, rightIndex + 1));
e.target.setSelectionRange(leftIndex, rightIndex + 1)
e.preventDefault()
}
}
}
}
</script>
<style lang="scss" scoped>
.active {
background-color: #1ABC9C;
color: #fff;
}
.app-container {
.el-row {
margin-bottom: 20px;
padding: 20px;
}
p {
color: #AAAAAA;
font-size: 12px;
margin: 0;
padding: 0;
line-height: 18px;
}
.add-btn {
color: #3BB19C;
}
.add-btn-border {
color: #1ABC9C;
border: 1px solid #1ABC9C;
padding: 5px 10px;
border-radius: 5px;
}
.del-btn-border {
color: #ff0062;
border: 1px solid #ff0062;
padding: 5px 10px;
border-radius: 5px;
}
.dis-row {
display: flex;
width: 100%;
justify-content: space-between;
}
.title {
color: #1ABC9C;
margin-bottom: 20px;
}
.item {
display: flex;
margin-bottom: 20px;
.item-key {
margin-right: 10px;
width: 80px;
}
.item-value {
flex: 1;
color: #7F7F7F;
}
.templateItemList {
display: flex;
flex-direction: column;
}
.templateItemList-item {
margin-bottom: 10px;
}
}
.messageExample {
.messageExample-contentBox {
font-size: 14px;
border: 1px solid #ccc;
.messageExample-contentBox-title {
font-weight: 700;
padding: 10px 10px 0;
}
.messageExample-contentBox-preContent {
padding: 10px 10px 0;
}
.messageExample-contentBox-item {
padding: 10px 10px 0;
}
.messageExample-contentBox-postContent {
padding: 10px 10px;
}
.messageExample-contentBox-seeDetail {
color: #aaa;
border-top: 1px solid #ccc;
margin-top: 10px;
padding: 10px;
display: flex;
justify-content: space-between;
}
}
}
}
</style>
element+ input光标插入关键词及删除关键词整体
最新推荐文章于 2024-04-22 11:40:00 发布