123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508 |
- <template>
- <div :id="`table-form-item-${keyId}`" v-loading="isLoading" :style="tableFormStyle"
- class="hc-table-form-data-item">
- <el-scrollbar v-if="isScroll" class="table-form-item-scrollbar">
- <div :id="`table-form-${keyId}`" class="hc-excel-table-form"/>
- </el-scrollbar>
- <div v-else :id="`table-form-${keyId}`" class="hc-excel-table-form"/>
- <div v-if="isTableForm === false" class="hc-no-table-form">
- <div class="table-form-no">
- <img :src="notableform" alt=""/>
- <div class="desc">{{ noTips }}</div>
- </div>
- </div>
- </div>
- </template>
- <script setup>
- import {ref, watch, onMounted, nextTick, onUnmounted} from "vue"
- import HTableForm from "~src/plugins/HTableForm"
- import notableform from '~src/assets/view/notableform.svg'
- import {getStoreData, setStoreData, delStoreData} from "~uti/storage";
- import {getObjNullValue, isString, deepClone, getIndex} from "vue-utils-plus"
- //初始
- const props = defineProps({
- pkey: [String, Number],
- noTip: {
- type: [String, Number],
- default: '暂无表单数据'
- },
- html: String,
- form: {
- type: Object,
- default: () => ({})
- },
- cols: {
- type: Array,
- default: () => ([])
- },
- loading: Boolean,
- scroll: {
- type: Boolean,
- default: true
- },
- height: {
- type: String,
- default: '100%'
- },
- width: {
- type: String,
- default: 'auto'
- },
- isMessage: {
- type: Boolean,
- default: true
- },
- })
- //初始变量
- const keyId = ref(props.pkey)
- const noTips = ref(props.noTip)
- const isScroll = ref(props.scroll)
- const isLoading = ref(props.loading)
- //表单数据
- const excelHtml = ref(props.html)
- const excelForm = ref(props.form)
- const colsKeys = ref(props.cols)
- //样式
- const tableFormApp = ref(null)
- const tableFormStyle = ref('')
- const isTableForm = ref(false)
- //监听
- watch(() => [props.pkey, props.noTip, props.scroll, props.loading, props.width, props.height], ([pkey, tip, scroll, loading, width, height]) => {
- keyId.value = pkey
- noTips.value = tip
- isScroll.value = scroll
- isLoading.value = loading
- setItemStyle(width, height)
- })
- //html变动
- watch(() => [
- props.html
- ], ([html]) => {
- excelHtml.value = html
- setExcelHtml()
- })
- //深度监听变动的对象数据
- watch(() => [
- props.form
- ], ([val]) => {
- excelForm.value = val
- setPickerKey()
- setFormData(val)
- }, {
- deep: true
- })
- //深度监听按键切换的key列表
- watch(() => [
- props.cols
- ], ([cols]) => {
- colsKeys.value = cols
- }, {
- deep: true
- })
- //渲染完成
- onMounted(() => {
- setItemStyle(props.width, props.height)
- setPickerKey()
- getExcelHtml()
- })
- //设置样式
- const setItemStyle = (width, height) => {
- tableFormStyle.value = `width: ${width}; height: ${height};`
- }
- //事件
- const emit = defineEmits(['rightTap', 'render'])
- //获取已填写的数据
- const setPickerKey = () => {
- HTableForm.setPickerKey(excelForm.value)
- }
- const setExcelHtml = () => {
- //先卸载
- if (tableFormApp.value) {
- tableFormApp.value?.unmount()
- }
- setPickerKey()
- getExcelHtml()
- }
- //获取模板标签数据
- const getExcelHtml = () => {
- const pkeyId = keyId.value
- const temp = isString(excelHtml.value) ? excelHtml.value : ''
- if (temp && pkeyId) {
- isTableForm.value = true
- //渲染表单
- tableFormApp.value = HTableForm.createForm({
- template: temp,
- tableForm: excelForm.value,
- keys: colsKeys.value,
- appId: `#table-form-${pkeyId}`,
- onRight: (event, KeyName) => {
- onRightClick(pkeyId, event, KeyName)
- },
- //表单正则效验
- onBlur: (event, key, reg, val, msg) => {
- setTableFormBlurReg(pkeyId, event, key, reg, val, msg)
- },
- onLeftClick: (key) => {
- setShiftTableForm(key)
- },
- })
- excelForm.value.isRenderForm = true
- nextTick(() => {
- HTableForm.setByClassKeyup(colsKeys.value)
- })
- } else {
- isTableForm.value = false
- excelForm.value.isRenderForm = false
- }
- emit('render', excelForm.value)
- }
- //正则效验
- const formRegExpJson = ref({})
- const setTableFormBlurReg = (pkeyId, event, key, reg, val, msg) => {
- const dom = document.getElementById(key)?.parentElement ?? ''
- if (dom) {
- if (val && reg) {
- let regx = new RegExp(reg);
- let state = regx.test(val);
- if (state) {
- delete formRegExpJson.value[key]
- HTableForm.setFormStyle(key, 'hc-red-border')
- } else {
- formRegExpJson.value[key] = {key, reg, val, msg, state}
- HTableForm.setFormStyle(key, 'hc-red-border', true)
- window?.$message?.warning(msg)
- }
- } else {
- delete formRegExpJson.value[key]
- HTableForm.setFormStyle(key, 'hc-red-border')
- }
- } else {
- delete formRegExpJson.value[key]
- }
- }
- //鼠标右键事件
- const onRightClick = (pkeyId, event, KeyName) => {
- //取光标位置
- const specialDom = document.getElementById(KeyName + "")
- const startPos = specialDom?.selectionStart || 0
- const endPos = specialDom?.selectionEnd || 0
- emit('rightTap', {event, KeyName, startPos, endPos, pkeyId})
- }
- const isCtrlKey = ref(false)
- const checkKeyList = ref([])
- const copyKeyList = ref(getStoreData('TableFormCopyKeyList') || [])
- //设置选择数据
- const setShiftTableForm = (key) => {
- if (isCtrlKey.value) {
- const form = excelForm.value
- const keys = checkKeyList.value
- const index = getIndex(keys, 'key', key)
- if (index === -1) {
- keys.push({key: key, val: form[key]})
- } else {
- keys.splice(index, 1)
- }
- checkKeyList.value = keys
- HTableForm.setCheckKeyStyle(key, index !== -1)
- }
- }
- //全局按键按下监听
- document.onkeydown = async (event) => {
- const {key, ctrlKey} = event
- //按下ctrl键
- if (ctrlKey && key === 'Control') {
- isCtrlKey.value = true
- }
- //按下复制快捷键
- if (ctrlKey && key === 'c') {
- const keysList = deepClone(checkKeyList.value)
- if (keysList.length > 0) {
- event.preventDefault()
- setStoreData('TableFormCopyKeyList', keysList)
- copyKeyList.value = keysList
- keysList.forEach(item => {
- HTableForm.setCheckKeyStyle(item['key'], true)
- })
- checkKeyList.value = []
- }
- }
- //按下粘贴快捷键
- if (ctrlKey && key === 'v') {
- const keysList = deepClone(copyKeyList.value)
- const checkList = checkKeyList.value
- if (checkList.length > 0) {
- event.preventDefault()
- //粘贴多个
- if (checkList.length > 1 && keysList.length > 1) {
- await setMultipleCheckValue(checkList, keysList)
- }
- //粘贴单个复制
- if (checkList.length > 1 && keysList.length === 1) {
- await setSingleCopyValue(checkList, keysList)
- }
- //复制单个粘贴
- if (checkList.length === 1 && keysList.length > 1) {
- await setCopySingleValue(checkList, keysList)
- }
- //清除缓存
- checkKeyList.value = []
- copyKeyList.value = []
- delStoreData('TableFormCopyKeyList')
- }
- }
- }
- //复制单个粘贴
- const setCopySingleValue = async (checkList, keysList) => {
- let form_val = '', key = checkList[0]['key']
- const form = excelForm.value
- for (let i = 0; i < keysList.length; i++) {
- const val = form[keysList[i]['key']]
- form_val = form_val ? form_val + '、' + val : val
- keysList.splice(0, 1) //删除第一个元素
- }
- await setTableFormInfoValue(key, form_val)
- HTableForm.setCheckKeyStyle(key, true)
- }
- //粘贴单个复制
- const setSingleCopyValue = async (checkList, keysList) => {
- const form = excelForm.value
- const form_val = form[keysList[0]['key']]
- for (let i = 0; i < checkList.length; i++) {
- const {key} = checkList[i]
- await setTableFormInfoValue(key, form_val)
- HTableForm.setCheckKeyStyle(key, true)
- }
- keysList.splice(0, 1) //删除第一个元素
- }
- //粘贴多个
- const setMultipleCheckValue = async (checkList, keysList) => {
- const form = excelForm.value
- for (let i = 0; i < checkList.length; i++) {
- const {key, val} = checkList[i]
- if (keysList.length > 0) {
- const form_val = form[keysList[0]['key']]
- await setTableFormInfoValue(key, form_val ? form_val : val)
- keysList.splice(0, 1) //删除第一个元素
- } else {
- await setTableFormInfoValue(key, val)
- }
- HTableForm.setCheckKeyStyle(key, true)
- }
- }
- //设置表单数据
- const setTableFormInfoValue = async (key, value) => {
- return new Promise((resolve) => {
- setTimeout(() => {
- excelForm.value[key] = value
- resolve(true)
- }, 100)
- })
- }
- //全局键盘放开监听
- document.onkeyup = (event) => {
- const {key, ctrlKey} = event
- if (!ctrlKey && key === 'Control') {
- isCtrlKey.value = false
- }
- }
- //卸载页面
- onUnmounted(() => {
- document.onkeydown = null
- document.onkeyup = null
- })
- //获取表单数据
- const getFormData = () => {
- return excelForm.value
- }
- //设置表单数据
- const setFormData = (data) => {
- nextTick(() => {
- excelForm.value = data
- })
- }
- //获取表单效验数据
- const getRegExpJson = () => {
- return deepClone(formRegExpJson.value);
- }
- //正则效验
- const isFormRegExp = async () => {
- const isRegExp = !!getObjNullValue(formRegExpJson.value)
- if (!isRegExp) {
- return true
- } else {
- window?.$message?.warning('请先修改完红色输入框的数据')
- return false
- }
- }
- //卸载渲染
- const unmountHtml = () => {
- if (tableFormApp.value) {
- tableFormApp.value?.unmount()
- }
- }
- // 暴露出去
- defineExpose({
- getFormData,
- setFormData,
- getRegExpJson,
- isFormRegExp,
- unmountHtml
- })
- </script>
- <style lang="scss">
- //插入特殊字符弹窗的输入框
- .hc-table-form-data-item .hc-excel-table-form td,
- .hc-table-form-data-item .hc-excel-table-form td .el-input .el-input__wrapper .el-input__inner,
- .el-form-item.special-form-item .el-form-item__content .el-input .el-input__wrapper .el-input__inner {
- font-family: "EUDC", 宋体, v-sans, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol" !important;
- }
- .hc-table-form-data-item {
- position: relative;
- padding: 12px;
- height: 100%;
- overflow: hidden;
- background-color: white;
- .hc-excel-table-form {
- position: relative;
- display: flex;
- padding: 10px;
- justify-content: center;
- td {
- padding: 6px;
- .el-input {
- background-color: #ffffff !important;
- border-radius: 3px;
- color: #606266;
- .el-input__wrapper {
- background-color: inherit;
- caret-color: var(--el-color-primary);
- }
- .el-input__suffix-inner {
- width: 18px;
- }
- }
- .el-textarea {
- width: 100%;
- height: 100%;
- .el-textarea__inner {
- min-height: initial !important;
- background-color: #ffffff;
- border-radius: 3px;
- color: #606266;
- height: 100%;
- caret-color: var(--el-color-primary);
- }
- }
- //日期选择框
- .el-date-editor.el-input .el-input__wrapper,
- .el-date-editor.el-date-editor--datetimerange.el-input__wrapper {
- height: 100%;
- width: 100%;
- }
- //焦点
- .el-input .el-input__wrapper.is-focus, .el-input .el-input__wrapper:hover,
- .el-textarea .el-textarea__inner:hover {
- box-shadow: 0 0 0 1.5px var(--el-input-focus-border-color) inset;
- background-color: #eddac4;
- }
- //公式
- &[gscolor] {
- .el-input, .el-textarea .el-textarea__inner {
- background-color: #dcdcdc !important;
- }
- }
- //文本选中颜色
- .el-input .el-input__wrapper input,
- .el-textarea textarea {
- &::selection {
- background: var(--el-color-primary-light-9);
- color: var(--el-color-primary);
- }
- &::-moz-selection {
- background: var(--el-color-primary-light-9);
- color: var(--el-color-primary);
- }
- }
- //下拉框
- .el-select {
- width: 100%;
- height: 100%;
- }
- }
- //非输入框颜色
- td:not([titlexx]), td[titlexx*=''],
- td:not([title]), td[title*=''] {
- background-color: white !important;
- user-select: none;
- }
- }
- .hc-no-table-form {
- position: relative;
- height: 100%;
- display: flex;
- justify-content: center;
- align-items: center;
- .table-form-no {
- position: relative;
- img {
- width: 350px;
- }
- .desc {
- text-align: center;
- font-size: 20px;
- color: #aaa;
- }
- }
- }
- }
- .hc-red-border {
- &.el-textarea__inner, &.el-input .el-input__wrapper {
- --el-input-border-color: #fe0000 !important;
- box-shadow: 0 0 0 2px #fe0000 inset !important;
- }
- }
- .hc-green-border {
- &.el-textarea__inner, &.el-input .el-input__wrapper {
- --el-input-border-color: #1ECC95 !important;
- box-shadow: 0 0 0 2px #1ECC95 inset !important;
- }
- }
- </style>
|