|
@@ -136,7 +136,7 @@ export default {
|
|
|
handler(val) {
|
|
|
if (val == null || this.isEdit != 1) return;
|
|
|
|
|
|
- this.$nextTick(() => {
|
|
|
+ this.$nextTick(async () => {
|
|
|
try {
|
|
|
if (!this.$refs.wordEditor) {
|
|
|
console.warn('编辑器未就绪');
|
|
@@ -149,6 +149,73 @@ export default {
|
|
|
let currentContent = this.com.content || '';
|
|
|
let insertContent = val.content;
|
|
|
|
|
|
+ // 如果是规格属性,先进行预处理
|
|
|
+ if (val.type === 'ProductAttr') {
|
|
|
+ // 构建规格HTML
|
|
|
+ const specs = val.attrs?.specifications?.[0];
|
|
|
+ if (specs) {
|
|
|
+ const prodAttrId = `${val.id}_${this.com.attrs?.length || 0}`;
|
|
|
+
|
|
|
+ let specHtml = `
|
|
|
+ <div class="product-attr-container">
|
|
|
+ <div class="spec-label">${specs.psp_name || '规格'}:</div>
|
|
|
+ <div class="spec-input">
|
|
|
+ `;
|
|
|
+
|
|
|
+ switch (specs.psp_type) {
|
|
|
+ case '单选':
|
|
|
+ const options = specs.psp_value ? specs.psp_value.split(',') : [];
|
|
|
+ specHtml += `
|
|
|
+ <select
|
|
|
+ id="${prodAttrId}"
|
|
|
+ data-index="${this.com.attrs?.length || 0}"
|
|
|
+ class="text-input-box product-select"
|
|
|
+ style="min-width: 120px;"
|
|
|
+ >
|
|
|
+ <option value="">请选择</option>
|
|
|
+ ${options.map(opt => `<option value="${opt}">${opt}</option>`).join('')}
|
|
|
+ </select>
|
|
|
+ `;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case '多选':
|
|
|
+ const multiOptions = specs.psp_value ? specs.psp_value.split(',') : [];
|
|
|
+ specHtml += `
|
|
|
+ <select
|
|
|
+ id="${prodAttrId}"
|
|
|
+ data-index="${this.com.attrs?.length || 0}"
|
|
|
+ class="text-input-box product-select"
|
|
|
+ multiple
|
|
|
+ style="min-width: 120px;"
|
|
|
+ >
|
|
|
+ ${multiOptions.map(opt => `<option value="${opt}">${opt}</option>`).join('')}
|
|
|
+ </select>
|
|
|
+ `;
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ specHtml += `
|
|
|
+ <input
|
|
|
+ type="text"
|
|
|
+ id="${prodAttrId}"
|
|
|
+ data-index="${this.com.attrs?.length || 0}"
|
|
|
+ class="text-input-box auto-width"
|
|
|
+ value="${specs.ps_name||0}"
|
|
|
+ placeholder="请输入${specs.psp_name || ''}"
|
|
|
+ style="min-width: 120px;"
|
|
|
+ >
|
|
|
+ `;
|
|
|
+ }
|
|
|
+
|
|
|
+ specHtml += `
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ `;
|
|
|
+
|
|
|
+ insertContent = specHtml;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
// 确保变量两侧有空格
|
|
|
if (insertContent.includes('{{') && insertContent.includes('}}')) {
|
|
|
insertContent = ` ${insertContent} `;
|
|
@@ -156,23 +223,16 @@ export default {
|
|
|
|
|
|
// 构建新内容
|
|
|
let newContent;
|
|
|
-
|
|
|
- // 如果编辑器支持选区
|
|
|
if (editor.getSelection) {
|
|
|
const selection = editor.getSelection();
|
|
|
if (selection) {
|
|
|
- // 替换选中的内容
|
|
|
- const start = selection.start || 0;
|
|
|
- const end = selection.end || start;
|
|
|
- newContent = currentContent.substring(0, start) +
|
|
|
- insertContent +
|
|
|
- currentContent.substring(end);
|
|
|
+ newContent = currentContent.substring(0, selection.start) +
|
|
|
+ insertContent +
|
|
|
+ currentContent.substring(selection.end);
|
|
|
} else {
|
|
|
- // 在末尾添加
|
|
|
newContent = currentContent + insertContent;
|
|
|
}
|
|
|
} else {
|
|
|
- // 在末尾添加
|
|
|
newContent = currentContent + insertContent;
|
|
|
}
|
|
|
|
|
@@ -187,31 +247,19 @@ export default {
|
|
|
// 强制重新渲染
|
|
|
this.keys = new Date().getTime();
|
|
|
|
|
|
- // 调用保存方法
|
|
|
- this.save({
|
|
|
+ // 保存更新
|
|
|
+ await this.save({
|
|
|
main: newContent
|
|
|
});
|
|
|
|
|
|
- // 确保视图更新
|
|
|
- this.$forceUpdate();
|
|
|
-
|
|
|
- // 同步到预览模式
|
|
|
- this.syncContent();
|
|
|
-
|
|
|
- // 记录操作日志
|
|
|
- console.log('内容插入成功:', {
|
|
|
- 原内容: currentContent,
|
|
|
- 插入内容: insertContent,
|
|
|
- 新内容: newContent
|
|
|
+ // 确保视图更新并绑定事件
|
|
|
+ this.$nextTick(() => {
|
|
|
+ this.bindProductAttrEvents();
|
|
|
+ this.$forceUpdate();
|
|
|
});
|
|
|
|
|
|
} catch (error) {
|
|
|
console.error('插入内容时出错:', error);
|
|
|
- console.error('错误详情:', {
|
|
|
- 编辑器: this.$refs.wordEditor,
|
|
|
- 内容: val.content,
|
|
|
- 当前内容: this.com.content
|
|
|
- });
|
|
|
}
|
|
|
});
|
|
|
},
|
|
@@ -244,12 +292,15 @@ export default {
|
|
|
this.$nextTick(() => {
|
|
|
this.initializeInputWidths();
|
|
|
this.syncContent();
|
|
|
+ this.bindProductAttrEvents();
|
|
|
});
|
|
|
},
|
|
|
updated() {
|
|
|
this.$nextTick(() => {
|
|
|
if (this.isEdit == '2') {
|
|
|
this.syncContent();
|
|
|
+ } else {
|
|
|
+ this.bindProductAttrEvents();
|
|
|
}
|
|
|
});
|
|
|
},
|
|
@@ -258,6 +309,10 @@ export default {
|
|
|
this.$el.removeEventListener("input", this.handleInputChange);
|
|
|
this.$el.removeEventListener("input", this.handleVariableNullInput);
|
|
|
this.$el.removeEventListener("blur", this.handleVariableNullBlur, true);
|
|
|
+ const inputs = this.$el.querySelectorAll('.text-input-box');
|
|
|
+ inputs.forEach(input => {
|
|
|
+ input.removeEventListener('change', this.handleProductAttrChange);
|
|
|
+ });
|
|
|
},
|
|
|
methods: {
|
|
|
/*canvas 添加 */
|
|
@@ -374,53 +429,100 @@ export default {
|
|
|
'">'
|
|
|
);
|
|
|
} else if (_this.com.attrs[i].type == "ProductAttr") {
|
|
|
- //处理产品属性值
|
|
|
let item = _this.com.attrs[i];
|
|
|
let prodAttrId = item.id + "_" + i;
|
|
|
- if (item.content == "") {
|
|
|
- item.content = item.attrs.value;
|
|
|
+
|
|
|
+ // 添加调试日志
|
|
|
+ console.log('ProductAttr item:', item);
|
|
|
+ console.log('ProductAttr specifications:', item.attrs?.specifications);
|
|
|
+
|
|
|
+ // 获取规格信息
|
|
|
+ const specs = item.attrs?.specifications?.[0];
|
|
|
+ if (!specs) {
|
|
|
+ console.warn('No specifications found for ProductAttr:', item);
|
|
|
+ continue;
|
|
|
}
|
|
|
- if (item.attrs.type == 1) {
|
|
|
- //输入框
|
|
|
- data = data.replace(
|
|
|
- "{{" + item.id + "}}",
|
|
|
- '<input type="text" id="' +
|
|
|
- prodAttrId +
|
|
|
- '" data-index="' +
|
|
|
- i +
|
|
|
- '" class="text-input-box" value="' +
|
|
|
- item.content +
|
|
|
- '">'
|
|
|
- );
|
|
|
+
|
|
|
+ // 添加规格名称显示
|
|
|
+ let specHtml = `
|
|
|
+ <div class="product-attr-container">
|
|
|
+ <div class="spec-label">${specs.psp_name || '规格'}:</div>
|
|
|
+ <div class="spec-input">
|
|
|
+ `;
|
|
|
+
|
|
|
+ // 根据psp_type决定渲染什么类型的输入控件
|
|
|
+ if (this.isEdit == '1') {
|
|
|
+ // 预览模式直接显示内容
|
|
|
+ specHtml += `<span class="preview-content">${item.content || ''}</span>`;
|
|
|
} else {
|
|
|
- //选择框
|
|
|
- let dataItem = item.attrs.valueItems.split(",");
|
|
|
- let selectHtml =
|
|
|
- '<select id="' +
|
|
|
- prodAttrId +
|
|
|
- '" data-index="' +
|
|
|
- i +
|
|
|
- '" class="text-input-box">';
|
|
|
- for (var l = 0; l < dataItem.length; l++) {
|
|
|
- if (item.content == dataItem[l]) {
|
|
|
- selectHtml +=
|
|
|
- '<option value="' +
|
|
|
- dataItem[l] +
|
|
|
- '" selected>' +
|
|
|
- dataItem[l] +
|
|
|
- "</option>";
|
|
|
- } else {
|
|
|
- selectHtml +=
|
|
|
- '<option value="' +
|
|
|
- dataItem[l] +
|
|
|
- '">' +
|
|
|
- dataItem[l] +
|
|
|
- "</option>";
|
|
|
- }
|
|
|
+ console.log(specs.psp_type);
|
|
|
+ switch (specs.psp_type) {
|
|
|
+ /* case '2': // 单选 */
|
|
|
+ case '单选':
|
|
|
+ // 处理单选下拉框
|
|
|
+ const options = specs.psp_value ? specs.psp_value.split(',') : [];
|
|
|
+ specHtml += `
|
|
|
+ <select
|
|
|
+ id="${prodAttrId}"
|
|
|
+ data-index="${i}"
|
|
|
+ class="text-input-box product-select"
|
|
|
+ style="min-width: 120px;"
|
|
|
+ >
|
|
|
+ <option value="">请选择</option>
|
|
|
+ ${options.map(opt => `
|
|
|
+ <option
|
|
|
+ value="${opt}"
|
|
|
+ ${item.content === opt ? 'selected' : ''}
|
|
|
+ >${opt}</option>
|
|
|
+ `).join('')}
|
|
|
+ </select>
|
|
|
+ `;
|
|
|
+ break;
|
|
|
+
|
|
|
+ /* case '3': // 多选 */
|
|
|
+ case '多选':
|
|
|
+ // 处理多选下拉框
|
|
|
+ const multiOptions = specs.psp_value ? specs.psp_value.split(',') : [];
|
|
|
+ const selectedValues = specs.ps_name ? specs.ps_name.split(',') : [];
|
|
|
+ specHtml += `
|
|
|
+ <select
|
|
|
+ id="${prodAttrId}"
|
|
|
+ data-index="${i}"
|
|
|
+ class="text-input-box product-select"
|
|
|
+ multiple
|
|
|
+ style="min-width: 120px;"
|
|
|
+ >
|
|
|
+ ${multiOptions.map(opt => `
|
|
|
+ <option
|
|
|
+ value="${opt}"
|
|
|
+ ${selectedValues.includes(opt) ? 'selected' : ''}
|
|
|
+ >${opt}</option>
|
|
|
+ `).join('')}
|
|
|
+ </select>
|
|
|
+ `;
|
|
|
+ break;
|
|
|
+
|
|
|
+ default: // 输入框
|
|
|
+ specHtml += `
|
|
|
+ <input
|
|
|
+ id="${prodAttrId}"
|
|
|
+ data-index="${i}"
|
|
|
+ class="text-input-box product-input"
|
|
|
+ value="${item.content || 0}"
|
|
|
+ placeholder="请输入${specs.psp_name || ''}"
|
|
|
+ style="min-width: 120px;"
|
|
|
+ >
|
|
|
+ `;
|
|
|
}
|
|
|
- selectHtml += "</select>";
|
|
|
- data = data.replace("{{" + item.id + "}}", selectHtml);
|
|
|
}
|
|
|
+
|
|
|
+ specHtml += `
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ `;
|
|
|
+
|
|
|
+ // 替换标记
|
|
|
+ data = data.replace("{{" + item.id + "}}", specHtml);
|
|
|
} else if (_this.com.attrs[i].type == "formual") {
|
|
|
//处理计算公式 不处理
|
|
|
let formual = await _this.analysisFormual(_this.com.attrs[i]);
|
|
@@ -1156,6 +1258,72 @@ export default {
|
|
|
// 保留空格和换行
|
|
|
return content.replace(/\s+/g, ' ').replace(/\n/g, '<br>');
|
|
|
},
|
|
|
+
|
|
|
+ handleProductAttrChange(event) {
|
|
|
+ const target = event.target;
|
|
|
+ const index = parseInt(target.dataset.index);
|
|
|
+ const item = this.com.attrs[index];
|
|
|
+
|
|
|
+ console.log('ProductAttr change:', {
|
|
|
+ target,
|
|
|
+ index,
|
|
|
+ item
|
|
|
+ });
|
|
|
+
|
|
|
+ if (!item || item.type !== 'ProductAttr') return;
|
|
|
+
|
|
|
+ let newValue;
|
|
|
+ if (target.multiple) {
|
|
|
+ // 处理多选
|
|
|
+ newValue = Array.from(target.selectedOptions)
|
|
|
+ .map(opt => opt.value)
|
|
|
+ .filter(Boolean)
|
|
|
+ .join(',');
|
|
|
+ } else {
|
|
|
+ newValue = target.value;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 更新内容
|
|
|
+ this.$set(item, 'content', newValue);
|
|
|
+
|
|
|
+ // 触发更新事件
|
|
|
+ this.$emit('onUpdateProdAttr', this.currentIndex, index, newValue);
|
|
|
+ },
|
|
|
+
|
|
|
+ handleProductAttrInput(event) {
|
|
|
+ // 处理输入框实时输入
|
|
|
+ const target = event.target;
|
|
|
+ if (target.classList.contains('product-input')) {
|
|
|
+ this.adjustInputWidth({ target });
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ bindProductAttrEvents() {
|
|
|
+ // 移除编辑模式判断,允许在所有模式下绑定事件
|
|
|
+ this.$nextTick(() => {
|
|
|
+ const inputs = this.$el.querySelectorAll('.product-input, .product-select');
|
|
|
+ console.log('Found product inputs:', inputs.length);
|
|
|
+
|
|
|
+ inputs.forEach(input => {
|
|
|
+ // 移除旧的事件监听
|
|
|
+ input.removeEventListener('change', this.handleProductAttrChange);
|
|
|
+ input.removeEventListener('input', this.handleProductAttrInput);
|
|
|
+ input.removeEventListener('blur', this.handleProductAttrChange);
|
|
|
+
|
|
|
+ // 确保输入控件是可交互的
|
|
|
+ input.removeAttribute('readonly');
|
|
|
+ input.removeAttribute('disabled');
|
|
|
+
|
|
|
+ // 添加新的事件监听
|
|
|
+ if (input.tagName.toLowerCase() === 'select') {
|
|
|
+ input.addEventListener('change', this.handleProductAttrChange);
|
|
|
+ } else {
|
|
|
+ input.addEventListener('input', this.handleProductAttrInput);
|
|
|
+ input.addEventListener('blur', this.handleProductAttrChange);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ });
|
|
|
+ }
|
|
|
},
|
|
|
};
|
|
|
</script>
|
|
@@ -1309,4 +1477,101 @@ export default {
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+::v-deep {
|
|
|
+ .product-attr-container {
|
|
|
+ display: inline-flex;
|
|
|
+ align-items: center;
|
|
|
+ // 调整容器高度和间距
|
|
|
+ min-height: 28px;
|
|
|
+ margin: 2px 4px;
|
|
|
+ vertical-align: middle;
|
|
|
+
|
|
|
+ .spec-label {
|
|
|
+ margin-right: 8px;
|
|
|
+ white-space: nowrap;
|
|
|
+ font-size: 14px;
|
|
|
+ line-height: 1.4;
|
|
|
+ }
|
|
|
+
|
|
|
+ .spec-input {
|
|
|
+ flex: 1;
|
|
|
+ min-width: 120px;
|
|
|
+ display: inline-flex;
|
|
|
+ align-items: center;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .product-input,
|
|
|
+ .product-select {
|
|
|
+ // 调整输入框和选择框的尺寸
|
|
|
+ height: 28px;
|
|
|
+ line-height: 26px;
|
|
|
+ padding: 0 8px;
|
|
|
+ margin: 0;
|
|
|
+ font-size: 14px;
|
|
|
+ border: 1px solid #dcdfe6;
|
|
|
+ border-radius: 4px;
|
|
|
+ color: #606266;
|
|
|
+ background-color: #fff;
|
|
|
+ transition: all 0.2s;
|
|
|
+
|
|
|
+ &:hover {
|
|
|
+ border-color: #c0c4cc;
|
|
|
+ }
|
|
|
+
|
|
|
+ &:focus {
|
|
|
+ border-color: #409eff;
|
|
|
+ outline: none;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .product-select {
|
|
|
+ padding-right: 25px;
|
|
|
+
|
|
|
+ &[multiple] {
|
|
|
+ // 调整多选下拉框的高度
|
|
|
+ height: auto;
|
|
|
+ min-height: 28px;
|
|
|
+ max-height: 120px;
|
|
|
+ padding: 2px;
|
|
|
+
|
|
|
+ option {
|
|
|
+ padding: 4px 8px;
|
|
|
+ line-height: 20px;
|
|
|
+
|
|
|
+ &:checked {
|
|
|
+ background-color: #409eff;
|
|
|
+ color: #fff;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 预览模式样式优化
|
|
|
+ .view-mode {
|
|
|
+ .product-attr-container {
|
|
|
+ margin: 0 2px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .product-input,
|
|
|
+ .product-select {
|
|
|
+ background-color: transparent;
|
|
|
+ min-width: 80px;
|
|
|
+
|
|
|
+ &:not(:focus) {
|
|
|
+ border-color: transparent;
|
|
|
+ }
|
|
|
+
|
|
|
+ &:hover {
|
|
|
+ border-color: #dcdfe6;
|
|
|
+ }
|
|
|
+
|
|
|
+ &:focus {
|
|
|
+ background-color: #fff;
|
|
|
+ border-color: #409eff;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
</style>
|