diff --git a/src/utils/modelConfigHelper.js b/src/utils/modelConfigHelper.js new file mode 100644 index 0000000..41e8ec9 --- /dev/null +++ b/src/utils/modelConfigHelper.js @@ -0,0 +1,160 @@ +// 模型配置共享工具函数 +// 供 Painting / Video descriptor 使用 + +/** + * 检测 dimension 配置模式 + * @param {object | null} config - 模型配置对象 + * @returns {object | null} + * - combined: { type: 'combined', config: dimension子对象, paramName: string } + * - split: { type: 'split', wParam: 宽度参数, hParam: 高度参数 } + * - null: 无 dimension 参数 + */ +export function getDimConfig(config) { + if (!config) return null + const dimParam = config.params.find((p) => p.ui === 'dimension') + if (dimParam) return { type: 'combined', config: dimParam.dimension, paramName: dimParam.name } + const wParam = config.params.find((p) => p.ui === 'dimensionWidth') + const hParam = config.params.find((p) => p.ui === 'dimensionHeight') + if (wParam && hParam) return { type: 'split', wParam, hParam } + return null +} + +/** + * 检查 showWhen 条件是否满足 + * @param {object} param - 参数定义(可能含 showWhen) + * @param {object} paramValues - 当前所有参数值 + * @returns {boolean} + */ +export function checkShowWhen(param, paramValues) { + if (!param.showWhen) return true + return Object.entries(param.showWhen).every(([key, expected]) => { + return paramValues[key] === expected + }) +} + +/** + * 将 API 返回的 config 同步到响应式 state + * + * state 对象需包含以下属性(均为 ref 或 reactive): + * modelConfig, paramValues, proportion, resolution, quantity, quality, + * customWidth, customHight, dimWidth, dimHeight, promptPlaceholder + */ +export function syncDefaults(config, state) { + const { + modelConfig, + paramValues, + proportion, + resolution, + quantity, + quality, + customWidth, + customHight, + dimWidth, + dimHeight, + promptPlaceholder + } = state + + modelConfig.value = config + if (!config) return + + // 1. dimension.separator → 生成 parse/format(在遍历 params 之前完成) + config.params.forEach((p) => { + if (p.ui === 'dimension' && p.dimension?.separator && !p.dimension.parse) { + const sep = p.dimension.separator + p.dimension.parse = (val) => { + const parts = (val || '').split(sep) + return { width: Number.parseInt(parts[0]) || 0, height: Number.parseInt(parts[1]) || 0 } + } + p.dimension.format = (w, h) => `${w}${sep}${h}` + } + }) + + // 2. 初始化 paramValues(已存在的 key 保留,避免切换模型时丢失值) + config.params.forEach((p) => { + if (!(p.name in paramValues)) { + paramValues[p.name] = p.default ?? (p.name === 'outputFormat' ? 'png' : '') + } + }) + + // 3. 同步专用 ref + const ratioParam = config.params.find((p) => p.ui === 'proportion') + if (ratioParam) proportion.value = ratioParam.default || '1:1' + + const resParam = config.params.find((p) => p.ui === 'resolution') + if (resParam) resolution.value = resParam.default || '2k' + + const qtyParam = config.params.find((p) => p.ui === 'quantity') + if (qtyParam) quantity.value = qtyParam.default || 1 + + const cwParam = config.params.find((p) => p.name === 'customWidth') + if (cwParam) customWidth.value = cwParam.default || 1024 + + const chParam = config.params.find((p) => p.name === 'customHight') + if (chParam) customHight.value = chParam.default || 1024 + + const qualityParam = config.params.find((p) => p.name === 'quality') + if (qualityParam) quality.value = qualityParam.default || 'medium' + + // 4. dimension 初始化 + const dc = getDimConfig(config) + if (dc?.type === 'split') { + dimWidth.value = dc.wParam.default || 1024 + dimHeight.value = dc.hParam.default || 1024 + } else if (dc?.type === 'combined') { + const dimParam = config.params.find((p) => p.name === dc.paramName) + const raw = dimParam?.default || '' + const parsed = dc.config.parse(raw) + dimWidth.value = parsed.width + dimHeight.value = parsed.height + } + + // 5. promptPlaceholder 同步 + if (config.promptPlaceholder) { + promptPlaceholder.value = config.promptPlaceholder + } +} + +/** + * 将专用 ref 的当前值回写到 paramValues + * (在 buildTaskBody 之前调用) + */ +export function syncParamValues(config, state) { + const { + paramValues, + proportion, + resolution, + quantity, + customWidth, + customHight, + dimWidth, + dimHeight, + quality + } = state + + const ratioParam = config?.params?.find((p) => p.ui === 'proportion') + if (ratioParam) paramValues[ratioParam.name] = proportion.value + + const resParam = config?.params?.find((p) => p.ui === 'resolution') + if (resParam) paramValues[resParam.name] = resolution.value + + const qtyParam = config?.params?.find((p) => p.ui === 'quantity') + if (qtyParam) paramValues[qtyParam.name] = quantity.value + + if (config?.params?.find((p) => p.name === 'customWidth')) { + paramValues.customWidth = customWidth.value + } + if (config?.params?.find((p) => p.name === 'customHight')) { + paramValues.customHight = customHight.value + } + if (config?.params?.find((p) => p.name === 'quality')) { + paramValues.quality = quality.value + } + + const dc = getDimConfig(config) + if (dc?.type === 'split') { + paramValues[dc.wParam.name] = dimWidth.value + paramValues[dc.hParam.name] = dimHeight.value + } else if (dc?.type === 'combined') { + paramValues[dc.paramName] = dc.config.format(dimWidth.value, dimHeight.value) + } +}