123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532 |
- <template>
- <div :id="`table-form-item-${keyId}`" v-loading="loading" :style="tableFormItemStyle"
- 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">暂无表单数据</div>
- </div>
- </div>
- </div>
- </template>
- <script setup>
- import {ref, watch, onMounted, nextTick, onUnmounted} from "vue"
- import {useAppStore} from "~src/store";
- import HTableForm from "~src/plugins/HTableForm"
- import notableform from '~src/assets/view/notableform.svg'
- import {getStoreData, setStoreData, delStoreData} from "~uti/storage";
- import {getObjNullValue, isAsyncFunction, isString, getArrValue, deepClone, getIndex} from "vue-utils-plus"
- const useAppState = useAppStore()
- //初始
- const props = defineProps({
- tid: { // 树节点
- type: [String, Number],
- default: ''
- },
- kid: { // pkeyId
- type: [String, Number],
- default: ''
- },
- classify: { // 类型
- type: [String, Number],
- default: ''
- },
- api: { //请求方法函数列表
- type: Object,
- default: () => ({
- dataInfo: null,
- bussCols: null,
- excelHtml: null
- })
- },
- height: { // 高度
- type: String,
- default: '100%'
- },
- width: { // 宽度
- type: String,
- default: 'auto'
- },
- scroll: { // 可否滚动
- type: Boolean,
- default: false
- },
- datas: { //变动的数据
- type: Object,
- default: () => ({})
- },
- nodeName: { // 表单名称
- type: String,
- default: ''
- },
- })
- //初始变量
- const projectId = ref(useAppState.getProjectId)
- const contractId = ref(useAppState.getContractId)
- const keyId = ref(props.kid ? props.kid + '' : '')
- const treeId = ref(props.tid)
- const classify = ref(props.classify)
- const apis = ref(props.api)
- const tableFormItemStyle = ref('')
- const loading = ref(false)
- const isScroll = ref(props.scroll)
- const changeData = ref(props.datas)
- const nodeNames = ref(props.nodeName)
- //监听
- watch(() => [
- useAppState.getProjectId,
- useAppState.getContractId,
- props.tid,
- props.kid,
- props.classify,
- props.width,
- props.height,
- props.scroll,
- props.nodeName
- ], ([project_id, contract_id, tree_id, key_id, cid, width, height, scroll, nodeName]) => {
- projectId.value = project_id
- contractId.value = contract_id
- treeId.value = tree_id
- keyId.value = key_id ? key_id + '' : ''
- classify.value = cid
- isScroll.value = scroll
- nodeNames.value = nodeName
- setItemStyle(width, height)
- })
- //深度监听变动的对象数据
- watch(() => [
- props.datas
- ], ([data]) => {
- changeData.value = data
- setFormChangeData(data)
- }, {deep: true})
- //渲染完成
- onMounted(async () => {
- let keys = []
- loading.value = true
- const {dataInfo, bussCols, excelHtml} = apis.value
- setItemStyle(props.width, props.height)
- //获取已填写的数据
- if (isAsyncFunction(dataInfo)) {
- await getTableFormInfo(keyId.value, dataInfo)
- }
- //按键key列表
- if (isAsyncFunction(bussCols)) {
- keys = await getHtmlBussColsApi(keyId.value, bussCols)
- }
- //渲染表单
- if (isAsyncFunction(excelHtml)) {
- await getExcelHtml(keyId.value, excelHtml, keys)
- }
- loading.value = false
- })
- const setFormChangeData = (data) => {
- const form = tableFormInfo.value
- tableFormInfo.value = {
- ...form,
- ...data
- }
- tableFormInfo.value = form
- }
- //设置样式
- const setItemStyle = (width, height) => {
- tableFormItemStyle.value = `width: ${width}; height: ${height};`
- }
- //事件
- const emit = defineEmits(['rightTap', 'render'])
- //渲染状态变量
- const isTableForm = ref(false)
- const tableFormInfo = ref({})
- //获取表单初始数据
- const getFormDataInit = () => {
- return {
- projectId: projectId.value,
- contractId: contractId.value,
- classify: classify.value,
- pkeyId: keyId.value,
- nodeId: treeId.value,
- isRenderForm: false,
- }
- }
- //获取已填写的数据
- const getTableFormInfo = async (pkeyId, func) => {
- if (pkeyId) {
- const {error, code, data} = await func({
- pkeyId: pkeyId
- }, false)
- const resData = getObjNullValue(data)
- if (!error && code === 200 && resData) {
- HTableForm.setPickerKey(resData)
- tableFormInfo.value = {
- ...resData,
- ...getFormDataInit(),
- ...changeData.value
- }
- } else {
- tableFormInfo.value = {
- ...getFormDataInit(),
- ...changeData.value
- }
- }
- } else {
- tableFormInfo.value = {}
- window?.$message?.warning('pkeyId为空')
- }
- }
- //获取按键切换输入框的key列表
- const getHtmlBussColsApi = async (pkeyId, func) => {
- if (pkeyId) {
- const {error, code, data} = await func({
- pkeyId: pkeyId
- }, false)
- if (!error && code === 200) {
- let keys = getArrValue(data);
- for (let i = 0; i < keys.length; i++) {
- if (keys[i].length <= 0) {
- keys.splice(i, 1)
- }
- }
- return keys;
- } else {
- return [];
- }
- } else {
- return [];
- }
- }
- //获取模板标签数据
- const getExcelHtml = async (pkeyId, func, keys) => {
- if (pkeyId) {
- const {error, code, data} = await func({
- pkeyId: pkeyId
- }, false)
- const resData = isString(data) ? data || '' : ''
- if (!error && code === 200 && resData) {
- isTableForm.value = true
- //渲染表单
- HTableForm.createForm({
- template: resData,
- tableForm: tableFormInfo.value,
- keys: keys,
- 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)
- },
- })
- tableFormInfo.value.isRenderForm = true
- await nextTick(() => {
- HTableForm.setByClassKeyup(keys)
- })
- } else {
- isTableForm.value = false
- tableFormInfo.value.isRenderForm = false
- window?.$message?.warning('暂无表单')
- }
- } else {
- isTableForm.value = false
- tableFormInfo.value.isRenderForm = false
- window?.$message?.warning('pkeyId为空')
- }
- emit('render', tableFormInfo.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 keys = checkKeyList.value
- const index = getIndex(keys, 'key', key)
- if (index === -1) {
- keys.push({key: key})
- } else {
- keys.splice(index, 1)
- }
- checkKeyList.value = keys
- HTableForm.setCheckKeyStyle(key, index !== -1)
- }
- }
- //全局按键按下监听
- document.onkeydown = (event) => {
- const {key, ctrlKey} = event
- //按下ctrl键
- if (ctrlKey && key === 'Control') {
- isCtrlKey.value = true
- }
- //按下复制快捷键
- if (ctrlKey && key === 'c') {
- const keysList = deepClone(checkKeyList.value)
- 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
- const form = tableFormInfo.value
- checkList.forEach((item) => {
- const form_key = item['key']
- const item_value = form[form_key]
- if (keysList.length > 0) {
- const val = form[keysList[0]['key']]
- tableFormInfo.value[form_key] = val ? val : item_value
- keysList.splice(0, 1) //删除第一个元素
- } else {
- tableFormInfo.value[form_key] = item_value
- }
- HTableForm.setCheckKeyStyle(form_key, true)
- })
- //清除缓存
- checkKeyList.value = []
- copyKeyList.value = []
- delStoreData('TableFormCopyKeyList')
- }
- }
- //全局键盘放开监听
- document.onkeyup = (event) => {
- const {key, ctrlKey} = event
- if (!ctrlKey && key === 'Control') {
- isCtrlKey.value = false
- }
- }
- //卸载页面
- onUnmounted(() => {
- document.onkeydown = null
- document.onkeyup = null
- })
- //获取表单数据
- const getFormData = () => {
- return tableFormInfo.value
- }
- //设置表单数据
- const setFormData = (data) => {
- nextTick(() => {
- tableFormInfo.value = data
- })
- }
- //获取表单效验数据
- const getRegExpJson = () => {
- return deepClone(formRegExpJson.value);
- }
- const getNodeName = () => {
- return nodeNames.value
- }
- //正则效验
- const isFormRegExp = async () => {
- const isRegExp = !!getObjNullValue(formRegExpJson.value)
- if (!isRegExp) {
- return true
- } else {
- window?.$message?.warning('请先修改完红色输入框的数据')
- return false
- }
- }
- // 暴露出去
- defineExpose({
- getFormData,
- setFormData,
- getRegExpJson,
- isFormRegExp,
- getNodeName
- })
- </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>
|