element+ input光标插入关键词及删除关键词整体

// 申请模板
<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>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值