|
@@ -2,7 +2,7 @@
|
|
|
<hc-drawer v-model="isShow" ui="hc-project-list-edit-element-drawer" to-id="hc-layout-box" is-close @close="drawerClose">
|
|
|
<hc-page-split :fold="false" :options="splitOptions">
|
|
|
<template #left>
|
|
|
- <hc-card :title="`【编辑元素】${dataInfo.tableName}`">
|
|
|
+ <hc-card :title="`【编辑元素】${dataInfo.tableName}`" :loading="tableFormLoading">
|
|
|
<template #search>
|
|
|
<div class="text-13px color-#f0720a">
|
|
|
<span>提示:鼠标右键功能:更换匹配元素字段、新增元素字段、删除匹配元素字段、公式配置</span>
|
|
@@ -11,13 +11,13 @@
|
|
|
<span class="text-green-6">绿色代表匹配成功</span>
|
|
|
</div>
|
|
|
</template>
|
|
|
- <hc-table-form ref="excelRef" :html="excelHtml" @tap="excelClick" />
|
|
|
+ <hc-table-form ref="excelRef" :html="excelHtml" is-warn @tap="excelClick" />
|
|
|
</hc-card>
|
|
|
</template>
|
|
|
<hc-card scrollbar>
|
|
|
<template #header>
|
|
|
- <el-button type="warning">表单调整</el-button>
|
|
|
- <el-button type="primary">公式配置</el-button>
|
|
|
+ <el-button type="warning" @click="formAdjustmentsClick">表单调整</el-button>
|
|
|
+ <el-button type="primary" @click="formulaConfigClick">公式配置</el-button>
|
|
|
</template>
|
|
|
<template #extra>
|
|
|
<el-button @click="drawerClose">返回上一级</el-button>
|
|
@@ -27,15 +27,16 @@
|
|
|
<el-input v-model="formModel.colName" placeholder="请点击左侧表单" disabled />
|
|
|
</el-form-item>
|
|
|
<el-form-item label="将元素替换为:" prop="htmlType">
|
|
|
- <el-select v-model="formModel.htmlType" filterable block placeholder="输入元素名称搜索">
|
|
|
- <el-option label="个人证书" :value="2" />
|
|
|
- <el-option label="企业证书" :value="6" />
|
|
|
+ <el-select v-model="formModel.htmlType" filterable block placeholder="输入元素名称搜索" @change="allElementChange">
|
|
|
+ <template v-for="item in allElement" :key="item.id">
|
|
|
+ <el-option :label="item.eName" :value="item.id" />
|
|
|
+ </template>
|
|
|
</el-select>
|
|
|
</el-form-item>
|
|
|
</el-form>
|
|
|
<div class="action-btn-box mb-40px mt-10px text-center">
|
|
|
- <el-button type="primary" @click="savingClick">临时保存</el-button>
|
|
|
- <el-button type="danger" style="margin-left: 50px">删除文本</el-button>
|
|
|
+ <el-button type="primary" :loading="submitLoading" @click="savingClick">临时保存</el-button>
|
|
|
+ <el-button type="danger" style="margin-left: 50px" :loading="submitLoading" @click="delElement">删除元素</el-button>
|
|
|
</div>
|
|
|
<div class="hc-edit-element-collapse">
|
|
|
<el-collapse v-model="activeNames">
|
|
@@ -44,33 +45,69 @@
|
|
|
<div class="hc-collapse-item-header hc-flex">
|
|
|
<div class="title text-green">本次临时保存的元素</div>
|
|
|
<div class="hc-extra-text-box">
|
|
|
- <el-button type="success" size="small" :loading="submitLoading" @click="dialogSubmit">全部提交保存</el-button>
|
|
|
+ <el-button type="success" size="small" :loading="submitLoading" @click.stop="dialogSubmit">全部提交保存</el-button>
|
|
|
</div>
|
|
|
</div>
|
|
|
</template>
|
|
|
- 1111
|
|
|
+ <hc-table ref="formArrRef" :column="tableColumn" :is-index="false" :datas="formDataArr">
|
|
|
+ <template #action="{ index }">
|
|
|
+ <el-link v-loading="submitLoading" type="danger" @click="rowDelClick(index)">删除</el-link>
|
|
|
+ </template>
|
|
|
+ </hc-table>
|
|
|
</el-collapse-item>
|
|
|
<el-collapse-item name="key2">
|
|
|
<template #title>
|
|
|
<div class="hc-collapse-item-header hc-flex">
|
|
|
<div class="title text-orange">未进行匹配的元素字段</div>
|
|
|
<div class="hc-extra-text-box">
|
|
|
- <el-button type="warning" size="small">新增元素</el-button>
|
|
|
+ <el-button type="warning" size="small" :loading="submitLoading" @click.stop="addElementClick">新增元素</el-button>
|
|
|
</div>
|
|
|
</div>
|
|
|
</template>
|
|
|
- 1111
|
|
|
+ <div class="hc-collapse-item-button">
|
|
|
+ <template v-for="item in matchElement" :key="item.id">
|
|
|
+ <el-button type="warning" size="small" plain @click="matchElementClick(item)">{{ item.eName }}</el-button>
|
|
|
+ </template>
|
|
|
+ <hc-empty v-if="matchElement.length <= 0" />
|
|
|
+ </div>
|
|
|
</el-collapse-item>
|
|
|
</el-collapse>
|
|
|
</div>
|
|
|
</hc-card>
|
|
|
+
|
|
|
+ <!-- 添加新的元素字段 -->
|
|
|
+ <hc-dialog v-model="isAddElementShow" ui="hc-project-list-edit-element-add-element" widths="50rem" is-table title="添加新的元素字段" :padding="false" @close="addElementClose">
|
|
|
+ <template #extra>
|
|
|
+ <el-button type="danger" size="small" @click="addElementData">新增元素</el-button>
|
|
|
+ </template>
|
|
|
+ <hc-table :column="addElementColumn" :datas="addElementTable" :is-current-row="false">
|
|
|
+ <template #eName="{ row }">
|
|
|
+ <hc-table-input v-model="row.eName" type="text" />
|
|
|
+ </template>
|
|
|
+ <template #eType="{ row }">
|
|
|
+ <el-select v-model="row.eType" filterable block>
|
|
|
+ <template v-for="item in dataType" :key="item.id">
|
|
|
+ <el-option :label="item.label" :value="item.value" />
|
|
|
+ </template>
|
|
|
+ </el-select>
|
|
|
+ </template>
|
|
|
+ <template #action="{ index }">
|
|
|
+ <el-link type="danger" @click="addElementDelClick(index)">删除</el-link>
|
|
|
+ </template>
|
|
|
+ </hc-table>
|
|
|
+ <template #footer>
|
|
|
+ <el-button hc-btn @click="addElementClose">取消</el-button>
|
|
|
+ <el-button hc-btn type="primary" :loading="addElementLoading" @click="addElementSubmit">确定</el-button>
|
|
|
+ </template>
|
|
|
+ </hc-dialog>
|
|
|
</hc-page-split>
|
|
|
</hc-drawer>
|
|
|
</template>
|
|
|
|
|
|
<script setup>
|
|
|
import { ref, watch } from 'vue'
|
|
|
-import { getArrValue, getObjValue, isNullES } from 'js-fast-way'
|
|
|
+import { arrIndex, deepClone, formValidate, getArrValue, getObjValue, isNullES } from 'js-fast-way'
|
|
|
+import { getDictionaryData } from '~uti/tools'
|
|
|
import excelApi from '~api/exctab/exceltab'
|
|
|
|
|
|
const props = defineProps({
|
|
@@ -85,7 +122,7 @@ const props = defineProps({
|
|
|
})
|
|
|
|
|
|
//事件
|
|
|
-const emit = defineEmits(['close'])
|
|
|
+const emit = defineEmits(['close', 'toPage'])
|
|
|
|
|
|
//双向绑定
|
|
|
const isShow = defineModel('modelValue', {
|
|
@@ -111,22 +148,68 @@ const splitOptions = { sizes: [70, 30], snapOffset: 0, minSize: [300, 300] }
|
|
|
//处理相关数据
|
|
|
const excelRef = ref(null)
|
|
|
const excelHtml = ref('')
|
|
|
+const tableFormLoading = ref(true)
|
|
|
const getDataApi = async () => {
|
|
|
const { pkeyId, excelId } = getObjValue(dataInfo.value)
|
|
|
if (isNullES(pkeyId) || isNullES(excelId)) {
|
|
|
+ tableFormLoading.value = false
|
|
|
window?.$message.warning('表单值异常,请联系管理员')
|
|
|
return
|
|
|
}
|
|
|
+ tableFormLoading.value = true
|
|
|
const { data } = await excelApi.getExcelHtml({ pkeyId })
|
|
|
excelHtml.value = data || ''
|
|
|
+ await getElementInfoByTabId()
|
|
|
+ await getUnMatchField()
|
|
|
+ getDataType().then()
|
|
|
+ tableFormLoading.value = false
|
|
|
+}
|
|
|
+
|
|
|
+//获取全部元素
|
|
|
+const allElement = ref([])
|
|
|
+const getElementInfoByTabId = async () => {
|
|
|
+ const { initTableId } = getObjValue(dataInfo.value)
|
|
|
+ const { data } = await excelApi.getElementInfoByTabId({
|
|
|
+ tabId: initTableId,
|
|
|
+ })
|
|
|
+ allElement.value = getArrValue(data)
|
|
|
+}
|
|
|
+const allElementChange = () => {
|
|
|
+ const { htmlType } = formModel.value
|
|
|
+ let info = getObjValue(allElement.value.find((item) => item.id === htmlType))
|
|
|
+ formModel.value.htmlName = info.eName
|
|
|
+}
|
|
|
+
|
|
|
+//提取未匹配的元素字段
|
|
|
+const matchElement = ref([])
|
|
|
+const getUnMatchField = async () => {
|
|
|
+ const { pkeyId, initTableId } = getObjValue(dataInfo.value)
|
|
|
+ const { data } = await excelApi.getUnMatchField({
|
|
|
+ pkeyId: pkeyId,
|
|
|
+ tabId: initTableId,
|
|
|
+ })
|
|
|
+ matchElement.value = getArrValue(data)
|
|
|
+}
|
|
|
+
|
|
|
+//未匹配的元素
|
|
|
+const matchElementClick = ({ id, eName }) => {
|
|
|
+ if (submitLoading.value) return
|
|
|
+ formModel.value.htmlType = id
|
|
|
+ formModel.value.htmlName = eName
|
|
|
+}
|
|
|
+
|
|
|
+//元素数据类型
|
|
|
+const dataType = ref([])
|
|
|
+const getDataType = async () => {
|
|
|
+ dataType.value = await getDictionaryData('data_type')
|
|
|
}
|
|
|
|
|
|
//基础表单
|
|
|
const formRef = ref(null)
|
|
|
const formModel = ref({})
|
|
|
const formRules = {
|
|
|
- colName: { required: true, trigger: 'change', message: '请先获取元素坐标' },
|
|
|
- htmlType: { required: true, trigger: 'change', message: '请先寻找将元素替换为' },
|
|
|
+ colName: { required: true, trigger: 'blur', message: '请先获取元素坐标' },
|
|
|
+ htmlType: { required: true, trigger: 'blur', message: '请先寻找将元素替换为' },
|
|
|
}
|
|
|
|
|
|
//元素被点击
|
|
@@ -138,14 +221,21 @@ const excelClick = async (item) => {
|
|
|
}
|
|
|
const data = await getDomAttribute(item)
|
|
|
const arr = getArrValue(formDataArr.value)
|
|
|
- console.log(data)
|
|
|
- /*formModel.value = {
|
|
|
+ const index = arrIndex(arr, 'key', data.key)
|
|
|
+ const colName = data.name || data.text || data.key
|
|
|
+ const htmlType = index !== -1 ? arr[index].htmlType : ''
|
|
|
+ const htmlName = index !== -1 ? arr[index].htmlName : ''
|
|
|
+ const type = index !== -1 ? arr[index].type : ''
|
|
|
+ formModel.value = {
|
|
|
tabId: pkeyId,
|
|
|
- colName: data.name || data.key,
|
|
|
+ colName: colName,
|
|
|
+ key: data.key,
|
|
|
tdIndex: data.td,
|
|
|
trIndex: data.tr,
|
|
|
- htmlType: '',
|
|
|
- }*/
|
|
|
+ htmlType: htmlType,
|
|
|
+ htmlName: htmlName,
|
|
|
+ type: type,
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
//获取元素相关信息
|
|
@@ -171,10 +261,62 @@ const getAttribute = async (dom, key) => {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+//临时保存表格
|
|
|
+const formArrRef = ref(null)
|
|
|
+const tableColumn = [
|
|
|
+ { key: 'colName', name: '元素坐标', minWidth: 120 },
|
|
|
+ { key: 'key', name: '元素位置', minWidth: 120 },
|
|
|
+ { key: 'htmlName', name: '匹配元素', minWidth: 120 },
|
|
|
+ { key: 'tdIndex', name: 'td', align: 'center', width: 60 },
|
|
|
+ { key: 'trIndex', name: 'tr', align: 'center', width: 60 },
|
|
|
+ { key: 'action', name: '操作', align: 'center', width: 70, fixed: 'right' },
|
|
|
+]
|
|
|
+
|
|
|
//临时保存
|
|
|
const formDataArr = ref([])
|
|
|
-const savingClick = () => {
|
|
|
+const savingClick = async () => {
|
|
|
+ const res = await formValidate(formRef.value)
|
|
|
+ if (!res) return
|
|
|
+ const form = deepClone(formModel.value)
|
|
|
+ const arr = formDataArr.value
|
|
|
+ const index = arrIndex(arr, 'key', form.key)
|
|
|
+ const obj = { ...form, type: '' }
|
|
|
+ if (index !== -1) {
|
|
|
+ arr[index] = obj
|
|
|
+ } else {
|
|
|
+ arr.push(obj)
|
|
|
+ }
|
|
|
+ formModel.value = {}
|
|
|
+ window?.$message.success('临时保存成功,记得点击下方的全部提交保存')
|
|
|
+}
|
|
|
|
|
|
+//删除元素
|
|
|
+const delElement = () => {
|
|
|
+ const form = deepClone(formModel.value)
|
|
|
+ if (isNullES(form.tdIndex) || isNullES(form.trIndex)) {
|
|
|
+ window?.$message.warning('请先在左侧表单,点击要删除的元素')
|
|
|
+ return
|
|
|
+ }
|
|
|
+ const arr = formDataArr.value
|
|
|
+ const index = arrIndex(arr, 'key', form.key)
|
|
|
+ const obj = {
|
|
|
+ ...form,
|
|
|
+ htmlType: null,
|
|
|
+ htmlName: '删除元素',
|
|
|
+ type: 'del',
|
|
|
+ }
|
|
|
+ if (index !== -1) {
|
|
|
+ arr[index] = obj
|
|
|
+ } else {
|
|
|
+ arr.push(obj)
|
|
|
+ }
|
|
|
+ formModel.value = {}
|
|
|
+ window?.$message.success('当前操作临时保存,记得点击下方的全部提交保存')
|
|
|
+}
|
|
|
+
|
|
|
+//删除临时保存
|
|
|
+const rowDelClick = (index) => {
|
|
|
+ formDataArr.value.splice(index, 1)
|
|
|
}
|
|
|
|
|
|
//折叠面板
|
|
@@ -183,12 +325,157 @@ const activeNames = ref(['key2'])
|
|
|
//保存数据
|
|
|
const submitLoading = ref(false)
|
|
|
const dialogSubmit = async () => {
|
|
|
- console.log(formModel.value)
|
|
|
+ const arr = deepClone(formDataArr.value)
|
|
|
+ if (arr.length <= 0) {
|
|
|
+ window?.$message.warning('请先添加要操作的元素')
|
|
|
+ return
|
|
|
+ }
|
|
|
+ //数据分类
|
|
|
+ submitLoading.value = true
|
|
|
+ let matchArr = [], delArr = []
|
|
|
+ for (let i = 0; i < arr.length; i++) {
|
|
|
+ if (arr[i].type === 'del') {
|
|
|
+ delArr.push({
|
|
|
+ ...arr[i],
|
|
|
+ colName: '/',
|
|
|
+ htmlName: null,
|
|
|
+ type: null,
|
|
|
+ })
|
|
|
+ } else {
|
|
|
+ matchArr.push({
|
|
|
+ ...arr[i],
|
|
|
+ colName: '',
|
|
|
+ htmlName: null,
|
|
|
+ type: null,
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+ await matchElementApi(matchArr)
|
|
|
+ await delElementApi(delArr)
|
|
|
+ window?.$message.success('操作完成')
|
|
|
+ clearFormData()
|
|
|
+ await getDataApi()
|
|
|
+ submitLoading.value = false
|
|
|
+}
|
|
|
+
|
|
|
+//匹配元素
|
|
|
+const matchElementApi = async (data) => {
|
|
|
+ if (data.length <= 0) return
|
|
|
+ await excelApi.saveTabColInfo(data)
|
|
|
+}
|
|
|
+
|
|
|
+//删除元素
|
|
|
+const delElementApi = async (arr, batchSize = 3) => {
|
|
|
+ if (arr.length <= 0) return
|
|
|
+ const totalBatches = Math.ceil(arr.length / batchSize)
|
|
|
+ let totalSuccess = 0, totalFail = 0
|
|
|
+ for (let i = 0; i < arr.length; i += batchSize) {
|
|
|
+ const batch = arr.slice(i, i + batchSize)
|
|
|
+ const currentBatch = Math.floor(i / batchSize) + 1
|
|
|
+ console.log(`正在处理第 ${currentBatch}/${totalBatches} 批`)
|
|
|
+
|
|
|
+ const results = await Promise.all(batch.map(async element => {
|
|
|
+ try {
|
|
|
+ await excelApi.delExcelElement(element)
|
|
|
+ return { element, success: true }
|
|
|
+ } catch (error) {
|
|
|
+ console.error(`删除元素 ${element} 时发生错误:`, error)
|
|
|
+ return { element, success: false, error }
|
|
|
+ }
|
|
|
+ }))
|
|
|
+ const batchSuccess = results.filter(r => r.success).length
|
|
|
+ const batchFail = results.filter(r => !r.success).length
|
|
|
+ totalSuccess += batchSuccess
|
|
|
+ totalFail += batchFail
|
|
|
+
|
|
|
+ console.log(`第 ${currentBatch} 批处理结果: 成功 ${batchSuccess}, 失败 ${batchFail}`)
|
|
|
+ }
|
|
|
+ console.log(`总计处理结果: 成功 ${totalSuccess}, 失败 ${totalFail}`)
|
|
|
+}
|
|
|
+
|
|
|
+//新增元素
|
|
|
+const isAddElementShow = ref(false)
|
|
|
+const addElementClick = () => {
|
|
|
+ addElementTable.value = [{ eName: '', eType: null }]
|
|
|
+ addElementLoading.value = false
|
|
|
+ isAddElementShow.value = true
|
|
|
+}
|
|
|
+
|
|
|
+//表格数据
|
|
|
+const addElementColumn = [
|
|
|
+ { key: 'eName', name: '清表元素名称' },
|
|
|
+ { key: 'eType', name: '元素数据类型' },
|
|
|
+ { key: 'action', name: '操作', align: 'center', width: 70, fixed: 'right' },
|
|
|
+]
|
|
|
+const addElementTable = ref([])
|
|
|
+
|
|
|
+//新增数据
|
|
|
+const addElementData = () => {
|
|
|
+ addElementTable.value.push({ eName: '', eType: null })
|
|
|
+}
|
|
|
+
|
|
|
+//删除
|
|
|
+const addElementDelClick = (index) => {
|
|
|
+ addElementTable.value.splice(index, 1)
|
|
|
+}
|
|
|
+
|
|
|
+//提交新增
|
|
|
+const addElementLoading = ref(false)
|
|
|
+const addElementSubmit = async () => {
|
|
|
+ const arr = addElementTable.value
|
|
|
+ if (arr.length <= 0) {
|
|
|
+ window?.$message.warning('请先添加元素字段')
|
|
|
+ return
|
|
|
+ }
|
|
|
+ const isValid = arr.every(val => val.eName && val.eType)
|
|
|
+ if (!isValid) {
|
|
|
+ window?.$message.warning('请先完善数据')
|
|
|
+ return
|
|
|
+ }
|
|
|
+ const { pid } = getObjValue(editData.value)
|
|
|
+ const { pkeyId, initTableName } = getObjValue(dataInfo.value)
|
|
|
+ const { isRes } = await excelApi.submitBatch({
|
|
|
+ projectId: pid,
|
|
|
+ initTableName,
|
|
|
+ id: pkeyId,
|
|
|
+ listData: arr,
|
|
|
+ })
|
|
|
+ if (!isRes) return
|
|
|
+ window?.$message.success('操作完成')
|
|
|
+ addElementClose()
|
|
|
+ await getElementInfoByTabId()
|
|
|
+ await getUnMatchField()
|
|
|
+}
|
|
|
+
|
|
|
+//关闭新增元素
|
|
|
+const addElementClose = () => {
|
|
|
+ isAddElementShow.value = false
|
|
|
+ addElementLoading.value = false
|
|
|
+ addElementTable.value = []
|
|
|
+}
|
|
|
+
|
|
|
+//表单调整
|
|
|
+const formAdjustmentsClick = () => {
|
|
|
+ drawerClose()
|
|
|
+ emit('toPage', 'adjustment')
|
|
|
+}
|
|
|
+
|
|
|
+//公式配置
|
|
|
+const formulaConfigClick = () => {
|
|
|
+ drawerClose()
|
|
|
+ emit('toPage', 'formula')
|
|
|
+}
|
|
|
+
|
|
|
+//清空数据
|
|
|
+const clearFormData = () => {
|
|
|
+ formModel.value = {}
|
|
|
+ formDataArr.value = []
|
|
|
}
|
|
|
|
|
|
//关闭抽屉
|
|
|
const drawerClose = () => {
|
|
|
isShow.value = false
|
|
|
+ clearFormData()
|
|
|
emit('close')
|
|
|
}
|
|
|
</script>
|
|
@@ -236,5 +523,19 @@ const drawerClose = () => {
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
+ .hc-collapse-item-button {
|
|
|
+ position: relative;
|
|
|
+ .el-button {
|
|
|
+ margin-right: 10px;
|
|
|
+ margin-bottom: 5px;
|
|
|
+ }
|
|
|
+ .el-button + .el-button {
|
|
|
+ margin-left: 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+.el-overlay-dialog .el-dialog.hc-new-dialog.hc-project-list-edit-element-add-element {
|
|
|
+ height: calc(100% - 300px);
|
|
|
+ --el-dialog-margin-top: 150px;
|
|
|
}
|
|
|
</style>
|