|
|
@@ -1,19 +1,458 @@
|
|
|
<template>
|
|
|
- <div>66666</div>
|
|
|
+ <div class="excelHtnl">
|
|
|
+ <div
|
|
|
+ class="excelBox hc-excel-table-form"
|
|
|
+ style="margin-top:40px;height: 100%;"
|
|
|
+ @click="parentClick($event)"
|
|
|
+ >
|
|
|
+ <div style="width:100%;height: 100%;overflow: scroll;" class='parent' :id="containerId"></div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
</template>
|
|
|
|
|
|
<script>
|
|
|
+import Vue from 'vue'
|
|
|
+import { getExcelHtml } from '@/api/exctab/excelmodel'
|
|
|
+
|
|
|
export default {
|
|
|
- name: "table-form-write",
|
|
|
- props: {
|
|
|
-
|
|
|
+ props: [
|
|
|
+ 'pkeyId',
|
|
|
+ 'initTableName',
|
|
|
+ 'selectedTableKey',
|
|
|
+ 'containerId',
|
|
|
+ 'multipleSelect' // 是否允许多选,默认为false
|
|
|
+ ],
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ selectedElements: [],
|
|
|
+ exHtml: '',
|
|
|
+ currentComponent: null
|
|
|
+ }
|
|
|
+ },
|
|
|
+ created() {
|
|
|
+ if (!this.containerId) {
|
|
|
+ this.containerId = `excel-container-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
|
+ }
|
|
|
+ },
|
|
|
+ watch: {
|
|
|
+ pkeyId: {
|
|
|
+ immediate: true,
|
|
|
+ deep: true,
|
|
|
+ handler(newVal) {
|
|
|
+ if (newVal) {
|
|
|
+ this.exHtml = ''
|
|
|
+ this.getExcelHtml(newVal)
|
|
|
+ } else {
|
|
|
+ this.exHtml = ''
|
|
|
+ this.clearForm()
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ selectedTableKey: {
|
|
|
+ handler(newKey) {
|
|
|
+ this.clearAllSelected();
|
|
|
+ if (newKey && newKey.startsWith('key_')) {
|
|
|
+ this.highlightElementsByKey(newKey);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ immediate: true
|
|
|
+ },
|
|
|
+ containerId: {
|
|
|
+ handler(newVal) {
|
|
|
+ this.clearForm()
|
|
|
+ this.selectedElements = [];
|
|
|
+ },
|
|
|
+ immediate: true
|
|
|
+ },
|
|
|
+ multipleSelect: {
|
|
|
+ handler(newVal) {
|
|
|
+ // 当多选模式改变时,清空当前选择
|
|
|
+ if (!newVal && this.selectedElements.length > 1) {
|
|
|
+ // 如果关闭多选且当前有多个选中,只保留最后一个
|
|
|
+ const lastElement = this.selectedElements[this.selectedElements.length - 1];
|
|
|
+ this.clearAllSelected();
|
|
|
+ this.selectElements([lastElement]);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ immediate: true
|
|
|
+ }
|
|
|
},
|
|
|
methods: {
|
|
|
+ // 获取当前组件容器元素,封装为工具方法
|
|
|
+ getContainer() {
|
|
|
+ return document.getElementById(this.containerId);
|
|
|
+ },
|
|
|
+
|
|
|
+ // 获取当前所有有橙色背景且去重的元素列表
|
|
|
+ getCurrentSelectedElements() {
|
|
|
+ const container = this.getContainer();
|
|
|
+ if (!container) return [];
|
|
|
+
|
|
|
+ // 获取所有有橙色背景的元素
|
|
|
+ const orangeElements = container.querySelectorAll('[style*="background-color: rgb(255, 165, 0)"], [style*="background-color:#ffa500"]');
|
|
|
+
|
|
|
+ // 根据 tableElementKey 去重
|
|
|
+ const uniqueElements = [];
|
|
|
+ const seenKeys = new Set();
|
|
|
+
|
|
|
+ orangeElements.forEach(el => {
|
|
|
+ if (el.id) {
|
|
|
+ const tableElementKey = this.initTableName + ':' + this.extractKeyPrefix(el.id);
|
|
|
+ if (!seenKeys.has(tableElementKey)) {
|
|
|
+ seenKeys.add(tableElementKey);
|
|
|
+ const keyName = el.placeholder || '';
|
|
|
+ uniqueElements.push({
|
|
|
+ tableElementKey: tableElementKey,
|
|
|
+ eName: keyName,
|
|
|
+ id: el.id
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ return uniqueElements;
|
|
|
+ },
|
|
|
+
|
|
|
+ highlightElementsByKey(key) {
|
|
|
+ if (!key) return;
|
|
|
+
|
|
|
+ const container = this.getContainer();
|
|
|
+ if (!container) return;
|
|
|
+
|
|
|
+ const keyPrefix = key.split('__')[0];
|
|
|
+ // 只在当前容器内查找元素
|
|
|
+ const samePrefixElements = container.querySelectorAll(`[id^="${keyPrefix}__"]`);
|
|
|
+
|
|
|
+ if (samePrefixElements.length === 0) {
|
|
|
+ const element = container.querySelector(`#${key}`);
|
|
|
+ if (element) {
|
|
|
+ this.selectElements([element]);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ this.selectElements(samePrefixElements);
|
|
|
+ },
|
|
|
+
|
|
|
+ async getExcelHtml(pkeyId) {
|
|
|
+ this.clearForm();
|
|
|
+ try {
|
|
|
+ const { data: res } = await getExcelHtml({ pkeyId })
|
|
|
+ if (res.code === 200) {
|
|
|
+ this.exHtml = res.data
|
|
|
+ this.cop();
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error('获取HTML失败:', error)
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ clearForm() {
|
|
|
+ const container = this.getContainer();
|
|
|
+ if (container) {
|
|
|
+ container.innerHTML = '';
|
|
|
+ }
|
|
|
+ this.clearAllSelected();
|
|
|
+ },
|
|
|
+
|
|
|
+ async cop() {
|
|
|
+ const container = this.getContainer();
|
|
|
+ if (!container) {
|
|
|
+ console.error('父容器不存在:', this.containerId);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ const MyComponent = Vue.extend({
|
|
|
+ template: this.exHtml,
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ formData: {},
|
|
|
+ getTokenHeader: {},
|
|
|
+ dap_site_data: {}
|
|
|
+ }
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ contextmenuClick() {},
|
|
|
+ getInformation() {},
|
|
|
+ formUploadSuccess() {},
|
|
|
+ formUploadExceed() {},
|
|
|
+ formUploadLoading() {},
|
|
|
+ delTableFormFile() {},
|
|
|
+ formUploadError() {},
|
|
|
+ uploadprogress() {},
|
|
|
+ formRemoteMethod() {},
|
|
|
+ getRegularExpression() {},
|
|
|
+ checkboxGroupChange() {},
|
|
|
+ formRemoteChange() {},
|
|
|
+ dateKeydown() {},
|
|
|
+ keyupShiftUp() {},
|
|
|
+ keyupShiftDown() {},
|
|
|
+ keyupShiftLeft() {},
|
|
|
+ keyupShiftRight() {},
|
|
|
+ inputLeftClick() {},
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ // 销毁旧组件
|
|
|
+ if (this.currentComponent) {
|
|
|
+ this.currentComponent.$destroy();
|
|
|
+ }
|
|
|
+
|
|
|
+ // 创建新组件
|
|
|
+ this.currentComponent = new MyComponent().$mount();
|
|
|
+
|
|
|
+ // 添加到当前容器
|
|
|
+ container.innerHTML = '';
|
|
|
+ container.appendChild(this.currentComponent.$el);
|
|
|
+
|
|
|
+ this.$nextTick(() => {
|
|
|
+ if (this.selectedTableKey) {
|
|
|
+ this.highlightElementsByKey(this.selectedTableKey);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ } catch (error) {
|
|
|
+ console.error('组件渲染失败:', error);
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ async parentClick(e) {
|
|
|
+ e.stopPropagation(); // 阻止事件冒泡到其他组件
|
|
|
+
|
|
|
+ const container = this.getContainer();
|
|
|
+ if (!container || !container.contains(e.target)) {
|
|
|
+ return; // 不是当前组件内的点击,不处理
|
|
|
+ }
|
|
|
+
|
|
|
+ // 检测Control键是否按下 (e.ctrlKey 对Windows/Linux有效,e.metaKey对Mac的Command键有效)
|
|
|
+ const isCtrlPressed = e.ctrlKey || e.metaKey;
|
|
|
+ // 只有在multipleSelect为true时才允许通过Control键进行多选
|
|
|
+ const isMultiSelectMode = this.multipleSelect && isCtrlPressed;
|
|
|
+
|
|
|
+ // 只在当前容器内查找目标元素
|
|
|
+ let target = e.target;
|
|
|
+ while (target && target !== container && !target.id) {
|
|
|
+ target = target.parentNode;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!target || !target.id || !container.contains(target)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 检查警告样式
|
|
|
+ let hasWarnStyle = false;
|
|
|
+ if (target.classList.contains('warnstyle') ||
|
|
|
+ (target.parentNode && target.parentNode.classList.contains('warnstyle'))) {
|
|
|
+ hasWarnStyle = true;
|
|
|
+ }
|
|
|
|
|
|
+ if (hasWarnStyle) {
|
|
|
+ this.$message({
|
|
|
+ type: "warning",
|
|
|
+ message: "当前位置未配置元素,请重新选择或配置元素后再试"
|
|
|
+ });
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ const id = target.id;
|
|
|
+ const elementId = this.initTableName + ':' + this.extractKeyPrefix(id);
|
|
|
+
|
|
|
+ // 检查是否已经有相同 tableElementKey 的元素被选中
|
|
|
+ const isSameKeySelected = this.selectedElements.some(item =>
|
|
|
+ item.tableElementKey === elementId
|
|
|
+ );
|
|
|
+
|
|
|
+ // 根据是否按下Control键决定是否清空已选元素
|
|
|
+ if (!isMultiSelectMode) {
|
|
|
+ this.clearAllSelected();
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!isSameKeySelected) {
|
|
|
+ if (id.startsWith('key_')) {
|
|
|
+ const keyPrefix = this.extractKeyPrefix(id);
|
|
|
+ // 只在当前容器内查找同前缀元素
|
|
|
+ const samePrefixElements = container.querySelectorAll(`[id^="${keyPrefix}__"]`);
|
|
|
+ this.selectElements(samePrefixElements);
|
|
|
+ } else {
|
|
|
+ this.handleNormalElement(target, id);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // 如果已经有相同 tableElementKey 的元素被选中,在多选模式下点击会取消选择所有相同key的元素
|
|
|
+ if (isMultiSelectMode) {
|
|
|
+ this.deselectElementsByKey(elementId);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ extractKeyPrefix(id) {
|
|
|
+ const parts = id.split('__');
|
|
|
+ return parts.length > 0 ? parts[0] : id;
|
|
|
+ },
|
|
|
+
|
|
|
+ selectElements(elements) {
|
|
|
+ const container = this.getContainer();
|
|
|
+ if (!container) return;
|
|
|
+
|
|
|
+ // 先取消选择所有相同 tableElementKey 的元素(避免重复)
|
|
|
+ if (elements.length > 0) {
|
|
|
+ const firstElementId = this.initTableName + ':' + this.extractKeyPrefix(elements[0].id);
|
|
|
+ this.deselectElementsByKey(firstElementId);
|
|
|
+ }
|
|
|
+
|
|
|
+ elements.forEach(el => {
|
|
|
+ // 确保元素属于当前容器
|
|
|
+ if (!container.contains(el)) return;
|
|
|
+
|
|
|
+ const index = this.selectedElements.findIndex(item => item.id === el.id);
|
|
|
+
|
|
|
+ if (index === -1) {
|
|
|
+ el.style.backgroundColor = '#ffa500';
|
|
|
+ const elementId = this.initTableName + ':' + this.extractKeyPrefix(el.id);
|
|
|
+ const keyName = el.placeholder || '';
|
|
|
+ const newElement = { tableElementKey: elementId, eName: keyName, id: el.id };
|
|
|
+ this.selectedElements.push(newElement);
|
|
|
+
|
|
|
+ // 传递当前所有有橙色背景且去重的元素
|
|
|
+ const currentSelected = this.getCurrentSelectedElements();
|
|
|
+ this.$emit('element-selected', newElement, true, currentSelected);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ // 取消选择所有具有相同 tableElementKey 的元素
|
|
|
+ deselectElementsByKey(tableElementKey) {
|
|
|
+ const container = this.getContainer();
|
|
|
+ if (!container) return;
|
|
|
+
|
|
|
+ // 找出所有相同 tableElementKey 的元素
|
|
|
+ const elementsToDeselect = this.selectedElements.filter(item =>
|
|
|
+ item.tableElementKey === tableElementKey
|
|
|
+ );
|
|
|
+
|
|
|
+ if (elementsToDeselect.length === 0) return;
|
|
|
+
|
|
|
+ // 清除样式并从选中列表中移除
|
|
|
+ elementsToDeselect.forEach(item => {
|
|
|
+ const element = container.querySelector(`#${item.id}`);
|
|
|
+ if (element) {
|
|
|
+ element.style.backgroundColor = '';
|
|
|
+ }
|
|
|
+ // 传递当前所有有橙色背景且去重的元素
|
|
|
+ const currentSelected = this.getCurrentSelectedElements();
|
|
|
+ this.$emit('element-selected', item, false, currentSelected);
|
|
|
+ });
|
|
|
+
|
|
|
+ // 从选中列表中移除这些元素
|
|
|
+ this.selectedElements = this.selectedElements.filter(item =>
|
|
|
+ item.tableElementKey !== tableElementKey
|
|
|
+ );
|
|
|
+ },
|
|
|
+
|
|
|
+ handleNormalElement(target, id) {
|
|
|
+ const container = this.getContainer();
|
|
|
+ if (!container || !container.contains(target)) return;
|
|
|
+
|
|
|
+ const elementId = this.initTableName + ':' + target.id.split('__')[0];
|
|
|
+ const keyName = target.placeholder || '';
|
|
|
+
|
|
|
+ if(!keyName){
|
|
|
+ this.$message({
|
|
|
+ type: "warning",
|
|
|
+ message: "当前位置未配置元素,请重新选择或配置元素后再试"
|
|
|
+ });
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 先取消选择相同 tableElementKey 的元素
|
|
|
+ this.deselectElementsByKey(elementId);
|
|
|
+
|
|
|
+ target.style.backgroundColor = '#ffa500';
|
|
|
+ const newElement = { tableElementKey: elementId, eName: keyName, id };
|
|
|
+ this.selectedElements.push(newElement);
|
|
|
+
|
|
|
+ // 传递当前所有有橙色背景且去重的元素
|
|
|
+ const currentSelected = this.getCurrentSelectedElements();
|
|
|
+ this.$emit('element-selected', newElement, true, currentSelected);
|
|
|
+ },
|
|
|
+
|
|
|
+ clearAllSelected() {
|
|
|
+ const container = this.getContainer();
|
|
|
+ if (!container) return;
|
|
|
+
|
|
|
+ this.selectedElements.forEach(item => {
|
|
|
+ // 只清除当前容器内的元素样式
|
|
|
+ const element = container.querySelector(`#${item.id}`);
|
|
|
+ if (element) {
|
|
|
+ element.style.backgroundColor = '';
|
|
|
+ // 传递当前所有有橙色背景且去重的元素
|
|
|
+ const currentSelected = this.getCurrentSelectedElements();
|
|
|
+ this.$emit('element-selected', {
|
|
|
+ tableElementKey: item.tableElementKey,
|
|
|
+ eName: item.eName,
|
|
|
+ id: item.id
|
|
|
+ }, false, currentSelected);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ this.selectedElements = [];
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
</script>
|
|
|
|
|
|
-<style scoped lang="scss">
|
|
|
-</style>
|
|
|
-
|
|
|
+<style lang="scss" scoped>
|
|
|
+/* 样式保持不变 */
|
|
|
+.excelHtnl {
|
|
|
+ margin: 0 0 0 10px;
|
|
|
+ background-color: #fff;
|
|
|
+ box-sizing: border-box;
|
|
|
+ padding: 0 20px 100px 20px;
|
|
|
+ height: 100%;
|
|
|
+}
|
|
|
+
|
|
|
+.hc-upload-table-form {
|
|
|
+ position: relative;
|
|
|
+ height: 100%;
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+}
|
|
|
+.hc-upload-table-form .el-upload {
|
|
|
+ position: relative;
|
|
|
+ flex: 1;
|
|
|
+ height: 100%;
|
|
|
+ color: #ccc;
|
|
|
+}
|
|
|
+.hc-upload-table-form .el-upload .hc-table-form-icon {
|
|
|
+ font-size: 24px;
|
|
|
+ font-weight: 100;
|
|
|
+}
|
|
|
+.hc-upload-table-form .el-upload .hc-table-form-img {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+}
|
|
|
+
|
|
|
+.excelBox {
|
|
|
+ ::v-deep .oldlace-bg {
|
|
|
+ background-color: oldlace;
|
|
|
+ }
|
|
|
+ ::v-deep .select-td {
|
|
|
+ border-width: 4px;
|
|
|
+ border-color: #E6A23C;
|
|
|
+ border-style: solid;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+::v-deep .warnstyle .el-input__inner {
|
|
|
+ background-image: url('/img/login/warn.png') !important;
|
|
|
+ background-repeat: no-repeat;
|
|
|
+ background-size: cover;
|
|
|
+ background-position: center
|
|
|
+}
|
|
|
+
|
|
|
+::v-deep .warnstyle .el-textarea__inner {
|
|
|
+ background-image: url('/img/login/warn.png') !important;
|
|
|
+ background-repeat: no-repeat;
|
|
|
+ background-position-x: 45%;
|
|
|
+ background-position-y: 46%;
|
|
|
+}
|
|
|
+</style>
|