fix(web): 修复编辑模板名称输入组件的标签嵌套问题
- 移除 el-input 标签的多余闭合标签 - 确保模板名称输入框结构符合规范 - 改善表单项的渲染正确性和稳定性
This commit is contained in:
parent
c0578b1d24
commit
18e2e372a0
|
|
@ -0,0 +1,9 @@
|
|||
---
|
||||
trigger: always_on
|
||||
---
|
||||
|
||||
# 项目规则
|
||||
|
||||
## 需求文档
|
||||
|
||||
@docs/需求文档.md
|
||||
|
|
@ -175,7 +175,7 @@
|
|||
</el-dialog>
|
||||
<el-dialog v-model="editVisible" title="编辑模板" :width="editWidth">
|
||||
<el-form ref="editFormRef" :model="edit" :rules="editRules" label-width="110px">
|
||||
<el-form-item label="模板名称" required show-message prop="name"><el-input v-model="edit.name" /></el-input></el-form-item>
|
||||
<el-form-item label="模板名称" required show-message prop="name"><el-input v-model="edit.name" /></el-form-item>
|
||||
<el-form-item label="数据源">
|
||||
<el-select v-model="edit.datasource" placeholder="选择" :teleported="false" style="width:160px">
|
||||
<el-option v-for="opt in datasourceOptions" :key="opt.value" :label="opt.label" :value="opt.value" />
|
||||
|
|
|
|||
109
web/main.js
109
web/main.js
|
|
@ -1,5 +1,23 @@
|
|||
const { createApp, reactive } = Vue;
|
||||
|
||||
// ==================== 常量定义 ====================
|
||||
const CONSTANTS = {
|
||||
// 轮询间隔(毫秒)
|
||||
JOBS_POLL_INTERVAL: 1000,
|
||||
// 树形选择器渲染延迟(毫秒)
|
||||
TREE_RENDER_DELAY: 100,
|
||||
// 编辑模式树渲染延迟(毫秒)
|
||||
TREE_EDIT_RENDER_DELAY: 300,
|
||||
// 对话框最小宽度
|
||||
DIALOG_MIN_WIDTH: 500,
|
||||
// 对话框最大宽度
|
||||
DIALOG_MAX_WIDTH: 1400,
|
||||
// 默认对话框宽度
|
||||
DIALOG_DEFAULT_WIDTH: 900,
|
||||
// 默认编辑对话框宽度
|
||||
DIALOG_EDIT_DEFAULT_WIDTH: 900
|
||||
};
|
||||
|
||||
const app = createApp({
|
||||
setup() {
|
||||
// ==================== 配置和工具函数 ====================
|
||||
|
|
@ -70,8 +88,8 @@ const app = createApp({
|
|||
editVisible: false,
|
||||
exportVisible: false,
|
||||
exportSubmitting: false,
|
||||
createWidth: localStorage.getItem('tplDialogWidth') || '900px',
|
||||
editWidth: localStorage.getItem('tplEditDialogWidth') || '900px',
|
||||
createWidth: localStorage.getItem('tplDialogWidth') || CONSTANTS.DIALOG_DEFAULT_WIDTH + 'px',
|
||||
editWidth: localStorage.getItem('tplEditDialogWidth') || CONSTANTS.DIALOG_EDIT_DEFAULT_WIDTH + 'px',
|
||||
edit: {
|
||||
id: null,
|
||||
name: '',
|
||||
|
|
@ -120,10 +138,21 @@ const app = createApp({
|
|||
const metaTableLabels = Vue.ref({});
|
||||
const recommendedMeta = Vue.ref([]);
|
||||
|
||||
const loadFieldsMeta = async (ds, type) => {
|
||||
/**
|
||||
* 加载字段元数据和推荐字段(合并为单次 API 调用)
|
||||
* @param {string} ds - 数据源
|
||||
* @param {number} type - 订单类型
|
||||
* @returns {Promise<string[]>} 推荐字段列表
|
||||
*/
|
||||
const loadFieldsMetaAndRecommended = async (ds, type) => {
|
||||
try {
|
||||
const res = await fetch(API_BASE + '/api/metadata/fields?datasource=' + encodeURIComponent(ds) + '&order_type=' + encodeURIComponent(String(type || 0)));
|
||||
if (!res.ok) {
|
||||
throw new Error(`加载字段元数据失败: ${res.status}`);
|
||||
}
|
||||
const data = await res.json();
|
||||
|
||||
// 处理表字段映射
|
||||
const tables = Array.isArray(data?.data?.tables) ? data.data.tables : (Array.isArray(data?.tables) ? data.tables : []);
|
||||
const m = {};
|
||||
const tblLabels = {};
|
||||
|
|
@ -135,25 +164,24 @@ const app = createApp({
|
|||
});
|
||||
metaFM.value = m;
|
||||
metaTableLabels.value = tblLabels;
|
||||
} catch (_e) {
|
||||
metaFM.value = {};
|
||||
metaTableLabels.value = {};
|
||||
}
|
||||
};
|
||||
|
||||
const loadRecommendedFields = async (ds, orderType) => {
|
||||
try {
|
||||
const res = await fetch(API_BASE + '/api/metadata/fields?datasource=' + encodeURIComponent(ds) + '&order_type=' + encodeURIComponent(String(orderType || 0)));
|
||||
const data = await res.json();
|
||||
// 处理推荐字段
|
||||
const rec = Array.isArray(data?.data?.recommended) ? data.data.recommended : (Array.isArray(data?.recommended) ? data.recommended : []);
|
||||
recommendedMeta.value = rec;
|
||||
return rec;
|
||||
} catch (_e) {
|
||||
} catch (e) {
|
||||
console.error('加载字段元数据失败:', e);
|
||||
metaFM.value = {};
|
||||
metaTableLabels.value = {};
|
||||
recommendedMeta.value = [];
|
||||
return [];
|
||||
}
|
||||
};
|
||||
|
||||
// 兼容旧接口
|
||||
const loadFieldsMeta = (ds, type) => loadFieldsMetaAndRecommended(ds, type);
|
||||
const loadRecommendedFields = (ds, orderType) => loadFieldsMetaAndRecommended(ds, orderType);
|
||||
|
||||
const getFieldsMap = (ds) => metaFM.value || {};
|
||||
|
||||
// ==================== 表标签映射 ====================
|
||||
|
|
@ -340,8 +368,15 @@ const app = createApp({
|
|||
const createFieldsTree = Vue.ref(null);
|
||||
const editFieldsTree = Vue.ref(null);
|
||||
|
||||
// 树形选择器复选框变化处理
|
||||
const onTreeCheck = (kind, data) => {
|
||||
/**
|
||||
* 树形选择器复选框变化处理
|
||||
* @param {string} kind - 操作类型: 'create' | 'edit'
|
||||
*/
|
||||
const onTreeCheck = (kind) => {
|
||||
if (kind !== 'create' && kind !== 'edit') {
|
||||
console.warn('onTreeCheck: 无效的 kind 参数', kind);
|
||||
return;
|
||||
}
|
||||
const tree = kind === 'create' ? createFieldsTree.value : editFieldsTree.value;
|
||||
if (!tree) return;
|
||||
|
||||
|
|
@ -455,7 +490,7 @@ const app = createApp({
|
|||
} catch (e) {
|
||||
console.warn('设置树形选择器选中状态失败:', e);
|
||||
}
|
||||
}, 100);
|
||||
}, CONSTANTS.TREE_RENDER_DELAY);
|
||||
});
|
||||
};
|
||||
|
||||
|
|
@ -476,9 +511,7 @@ const app = createApp({
|
|||
}
|
||||
});
|
||||
|
||||
// 兼容级联选择器的函数(已废弃,保留以避免错误)
|
||||
const onCascaderVisible = () => {};
|
||||
const onFieldsSelChange = () => {};
|
||||
// 废弃的函数已移除,如需调用请检查代码
|
||||
|
||||
// ==================== 表单验证规则 ====================
|
||||
const createRules = {
|
||||
|
|
@ -545,10 +578,14 @@ const app = createApp({
|
|||
const loadCreators = async () => {
|
||||
try {
|
||||
const res = await fetch(API_BASE + '/api/creators');
|
||||
if (!res.ok) {
|
||||
throw new Error(`加载创建者列表失败: ${res.status}`);
|
||||
}
|
||||
const data = await res.json();
|
||||
const arr = Array.isArray(data?.data) ? data.data : (Array.isArray(data) ? data : []);
|
||||
creatorOptions.value = arr.map(it => ({ label: it.name || String(it.id), value: Number(it.id) }));
|
||||
} catch (_e) {
|
||||
} catch (e) {
|
||||
console.error('加载创建者列表失败:', e);
|
||||
creatorOptions.value = [];
|
||||
}
|
||||
};
|
||||
|
|
@ -558,10 +595,14 @@ const app = createApp({
|
|||
const uid = getUserId();
|
||||
const url = API_BASE + '/api/ymt/users?limit=2000' + (uid ? ('&q=' + encodeURIComponent(uid)) : '');
|
||||
const res = await fetch(url);
|
||||
if (!res.ok) {
|
||||
throw new Error(`加载易码通用户列表失败: ${res.status}`);
|
||||
}
|
||||
const data = await res.json();
|
||||
const arr = Array.isArray(data?.data) ? data.data : (Array.isArray(data) ? data : []);
|
||||
ymtCreatorOptions.value = arr.map(it => ({ label: it.name || String(it.id), value: Number(it.id) }));
|
||||
} catch (_e) {
|
||||
} catch (e) {
|
||||
console.error('加载易码通用户列表失败:', e);
|
||||
ymtCreatorOptions.value = [];
|
||||
}
|
||||
};
|
||||
|
|
@ -574,10 +615,14 @@ const app = createApp({
|
|||
}
|
||||
try {
|
||||
const res = await fetch(API_BASE + '/api/resellers?creator=' + ids.join(','));
|
||||
if (!res.ok) {
|
||||
throw new Error(`加载分销商列表失败: ${res.status}`);
|
||||
}
|
||||
const data = await res.json();
|
||||
const arr = Array.isArray(data?.data) ? data.data : (Array.isArray(data) ? data : []);
|
||||
resellerOptions.value = arr.map(it => ({ label: (it.name || '') + (it.name ? '' : ''), value: Number(it.id) }));
|
||||
} catch (_e) {
|
||||
} catch (e) {
|
||||
console.error('加载分销商列表失败:', e);
|
||||
resellerOptions.value = [];
|
||||
}
|
||||
};
|
||||
|
|
@ -593,10 +638,14 @@ const app = createApp({
|
|||
qs.set('user_id', String(uid));
|
||||
qs.set('limit', '2000');
|
||||
const res = await fetch(API_BASE + '/api/ymt/merchants?' + qs.toString());
|
||||
if (!res.ok) {
|
||||
throw new Error(`加载客户列表失败: ${res.status}`);
|
||||
}
|
||||
const data = await res.json();
|
||||
const arr = Array.isArray(data?.data) ? data.data : (Array.isArray(data) ? data : []);
|
||||
ymtMerchantOptions.value = arr.map(it => ({ label: `${it.id} - ${it.name || ''}`, value: Number(it.id) }));
|
||||
} catch (_e) {
|
||||
} catch (e) {
|
||||
console.error('加载客户列表失败:', e);
|
||||
ymtMerchantOptions.value = [];
|
||||
}
|
||||
};
|
||||
|
|
@ -612,10 +661,14 @@ const app = createApp({
|
|||
qs.set('merchant_id', String(mid));
|
||||
qs.set('limit', '2000');
|
||||
const res = await fetch(API_BASE + '/api/ymt/activities?' + qs.toString());
|
||||
if (!res.ok) {
|
||||
throw new Error(`加载活动列表失败: ${res.status}`);
|
||||
}
|
||||
const data = await res.json();
|
||||
const arr = Array.isArray(data?.data) ? data.data : (Array.isArray(data) ? data : []);
|
||||
ymtActivityOptions.value = arr.map(it => ({ label: `${it.id} - ${it.name || ''}`, value: Number(it.id) }));
|
||||
} catch (_e) {
|
||||
} catch (e) {
|
||||
console.error('加载活动列表失败:', e);
|
||||
ymtActivityOptions.value = [];
|
||||
}
|
||||
};
|
||||
|
|
@ -630,10 +683,14 @@ const app = createApp({
|
|||
const qs = new URLSearchParams();
|
||||
qs.set('reseller', String(rid));
|
||||
const res = await fetch(API_BASE + '/api/plans?' + qs.toString());
|
||||
if (!res.ok) {
|
||||
throw new Error(`加载计划列表失败: ${res.status}`);
|
||||
}
|
||||
const data = await res.json();
|
||||
const arr = Array.isArray(data?.data) ? data.data : (Array.isArray(data) ? data : []);
|
||||
planOptions.value = arr.map(it => ({ label: `${it.id} - ${it.title || ''}`, value: Number(it.id) }));
|
||||
} catch (_e) {
|
||||
} catch (e) {
|
||||
console.error('加载计划列表失败:', e);
|
||||
planOptions.value = [];
|
||||
}
|
||||
};
|
||||
|
|
@ -925,7 +982,7 @@ const app = createApp({
|
|||
await Vue.nextTick();
|
||||
setTimeout(() => {
|
||||
setTreeChecked('edit', paths);
|
||||
}, 300);
|
||||
}, CONSTANTS.TREE_EDIT_RENDER_DELAY);
|
||||
} catch (_e) {
|
||||
state.edit.name = row.name;
|
||||
state.edit.datasource = row.datasource || 'marketing';
|
||||
|
|
|
|||
Loading…
Reference in New Issue