From 18e2e372a06c5a1ffb50f94ea93d6fe42323f744 Mon Sep 17 00:00:00 2001 From: zhouyonggao <1971162852@qq.com> Date: Wed, 17 Dec 2025 09:28:11 +0800 Subject: [PATCH] =?UTF-8?q?fix(web):=20=E4=BF=AE=E5=A4=8D=E7=BC=96?= =?UTF-8?q?=E8=BE=91=E6=A8=A1=E6=9D=BF=E5=90=8D=E7=A7=B0=E8=BE=93=E5=85=A5?= =?UTF-8?q?=E7=BB=84=E4=BB=B6=E7=9A=84=E6=A0=87=E7=AD=BE=E5=B5=8C=E5=A5=97?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 移除 el-input 标签的多余闭合标签 - 确保模板名称输入框结构符合规范 - 改善表单项的渲染正确性和稳定性 --- .qoder/rules/index.md | 9 ++++ web/index.html | 2 +- web/main.js | 111 ++++++++++++++++++++++++++++++++---------- 3 files changed, 94 insertions(+), 28 deletions(-) create mode 100644 .qoder/rules/index.md diff --git a/.qoder/rules/index.md b/.qoder/rules/index.md new file mode 100644 index 0000000..5275caf --- /dev/null +++ b/.qoder/rules/index.md @@ -0,0 +1,9 @@ +--- +trigger: always_on +--- + +# 项目规则 + +## 需求文档 + +@docs/需求文档.md diff --git a/web/index.html b/web/index.html index 545b77b..345f95e 100644 --- a/web/index.html +++ b/web/index.html @@ -175,7 +175,7 @@ - + diff --git a/web/main.js b/web/main.js index e366cbb..611f924 100644 --- a/web/main.js +++ b/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} 推荐字段列表 + */ + 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';