fix:修改json格式参数展示
This commit is contained in:
@@ -419,16 +419,18 @@
|
||||
</el-form-item>
|
||||
<!-- number 类型显示范围配置 -->
|
||||
<template v-if="currentParam?.type === 'number'">
|
||||
<el-divider content-position="left">数值范围配置</el-divider>
|
||||
<el-divider content-position="left">数值范围配置(phase)</el-divider>
|
||||
<el-form-item label="范围类型" prop="range_type">
|
||||
<el-select v-model="paramValueForm.range_type" placeholder="请选择范围类型" style="width: 100%">
|
||||
<el-option label="大于 (after)" value="after" />
|
||||
<el-option label="小于 (before)" value="before" />
|
||||
<el-option label="小于等于 (before)" value="before" />
|
||||
<el-option label="大于等于 (after)" value="after" />
|
||||
<el-option label="等于 (equal)" value="equal" />
|
||||
</el-select>
|
||||
<div class="form-tip">before: 数值 ≤ phase 时匹配 | after: 数值 ≥ phase 时匹配</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="范围值" prop="attr_range">
|
||||
<el-input-number v-model="paramValueForm.attr_range" placeholder="范围值" style="width: 100%" />
|
||||
<el-form-item label="阈值" prop="attr_range">
|
||||
<el-input-number v-model="paramValueForm.attr_range" :min="0" placeholder="范围阈值" style="width: 100%" />
|
||||
<div class="form-tip">例如:phase=100, rangeType=before 表示 0-100 范围</div>
|
||||
</el-form-item>
|
||||
</template>
|
||||
<el-form-item label="排序索引" prop="index">
|
||||
@@ -516,7 +518,7 @@
|
||||
<el-dialog
|
||||
v-model="planFormDialogVisible"
|
||||
:title="planFormType === 'add' ? '新增套餐' : '编辑套餐'"
|
||||
width="600px"
|
||||
width="700px"
|
||||
append-to-body
|
||||
>
|
||||
<el-form
|
||||
@@ -529,20 +531,137 @@
|
||||
<el-input v-model="planForm.name" placeholder="请输入套餐名称" />
|
||||
</el-form-item>
|
||||
<el-form-item label="说明" prop="note">
|
||||
<el-input v-model="planForm.note" type="textarea" :rows="3" placeholder="请输入套餐说明" />
|
||||
<el-input v-model="planForm.note" type="textarea" :rows="2" placeholder="请输入套餐说明" />
|
||||
</el-form-item>
|
||||
<el-form-item label="参数配置" prop="args">
|
||||
<el-input
|
||||
v-model="planForm.args"
|
||||
type="textarea"
|
||||
:rows="4"
|
||||
placeholder='JSON格式,如:[{"arg_id":1,"name":"参数名","attr_id":1,"value":"值"}]'
|
||||
/>
|
||||
<div class="form-tip">参数配置为JSON数组格式</div>
|
||||
<div class="args-config-container">
|
||||
<!-- 参数选择下拉框 -->
|
||||
<div class="args-select-row">
|
||||
<el-select
|
||||
v-model="selectedArgIds"
|
||||
multiple
|
||||
placeholder="请选择需要配置的参数"
|
||||
style="width: 100%"
|
||||
@change="onSelectedArgsChange"
|
||||
>
|
||||
<el-option
|
||||
v-for="spec in planSpecList"
|
||||
:key="spec.id"
|
||||
:label="spec.name"
|
||||
:value="spec.id"
|
||||
/>
|
||||
</el-select>
|
||||
</div>
|
||||
|
||||
<!-- 已选参数的值配置区域 -->
|
||||
<div v-if="selectedArgSpecs.length > 0" class="args-selector">
|
||||
<div
|
||||
v-for="spec in selectedArgSpecs"
|
||||
:key="spec.id"
|
||||
class="spec-item"
|
||||
>
|
||||
<div class="spec-label">{{ spec.name }}</div>
|
||||
<div class="spec-values">
|
||||
<!-- select 类型:显示可选值 -->
|
||||
<template v-if="spec.type === 'select' && spec.attrs && spec.attrs.length > 0">
|
||||
<el-radio-group
|
||||
v-model="selectedArgs[spec.id]"
|
||||
size="small"
|
||||
@change="updateArgsJson"
|
||||
>
|
||||
<el-radio-button
|
||||
v-for="attr in spec.attrs"
|
||||
:key="attr.id"
|
||||
:value="attr.id"
|
||||
>
|
||||
{{ attr.name }}
|
||||
</el-radio-button>
|
||||
</el-radio-group>
|
||||
</template>
|
||||
<!-- number 类型:数字输入 -->
|
||||
<template v-else-if="spec.type === 'number'">
|
||||
<div class="number-input-wrapper">
|
||||
<el-input-number
|
||||
v-model="selectedArgs[spec.id]"
|
||||
:min="spec.min || 0"
|
||||
:max="spec.max || 9999"
|
||||
:step="spec.step || 1"
|
||||
:step-strictly="true"
|
||||
size="small"
|
||||
@change="updateArgsJson"
|
||||
/>
|
||||
<span class="number-range">
|
||||
(范围: {{ spec.min || 0 }} - {{ spec.max || 9999 }},步长: {{ spec.step || 1 }})
|
||||
</span>
|
||||
</div>
|
||||
<!-- 显示匹配的价格区间 -->
|
||||
<div v-if="spec.attrs && spec.attrs.length > 0 && selectedArgs[spec.id]" class="matched-attr-info">
|
||||
<el-tag type="success" size="small">
|
||||
匹配区间: {{ getMatchedAttrName(spec, selectedArgs[spec.id]) }}
|
||||
</el-tag>
|
||||
</div>
|
||||
</template>
|
||||
<!-- string 类型:文本输入 -->
|
||||
<template v-else>
|
||||
<el-input
|
||||
v-model="selectedArgs[spec.id]"
|
||||
placeholder="请输入值"
|
||||
size="small"
|
||||
style="width: 200px"
|
||||
@input="updateArgsJson"
|
||||
/>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<el-empty v-else-if="planSpecList.length > 0" description="请先选择需要配置的参数" :image-size="60" />
|
||||
<el-empty v-else description="暂无参数配置,请先为商品添加参数" :image-size="60" />
|
||||
|
||||
<!-- 查看JSON按钮 -->
|
||||
<div class="args-actions" v-if="selectedArgSpecs.length > 0">
|
||||
<el-button type="info" plain size="small" @click="showArgsPreview = true">
|
||||
<el-icon><View /></el-icon>
|
||||
查看配置JSON
|
||||
</el-button>
|
||||
<el-button type="warning" plain size="small" @click="clearArgsSelection">
|
||||
<el-icon><Delete /></el-icon>
|
||||
清空选择
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="额外参数" prop="extra_arg_ids">
|
||||
<el-input v-model="planForm.extra_arg_ids" placeholder="额外参数ID,如:1,2,3" />
|
||||
<div class="form-tip">多个参数ID用英文逗号分隔</div>
|
||||
<el-form-item label="额外参数">
|
||||
<div class="args-config-container">
|
||||
<div class="form-tip" style="margin-bottom: 8px;">选择参数配置中未选择的参数作为额外参数(只需参数ID,不需要选择值)</div>
|
||||
<!-- 额外参数下拉选择 -->
|
||||
<el-select
|
||||
v-model="selectedExtraArgIds"
|
||||
multiple
|
||||
placeholder="请选择额外参数"
|
||||
style="width: 100%"
|
||||
@change="onSelectedExtraArgsChange"
|
||||
>
|
||||
<el-option
|
||||
v-for="spec in extraSpecList"
|
||||
:key="spec.id"
|
||||
:label="`${spec.name} (ID: ${spec.id})`"
|
||||
:value="spec.id"
|
||||
/>
|
||||
</el-select>
|
||||
<!-- 已选额外参数展示 -->
|
||||
<!-- <div v-if="selectedExtraArgIds.length > 0" class="extra-args-display">
|
||||
<el-tag
|
||||
v-for="argId in selectedExtraArgIds"
|
||||
:key="argId"
|
||||
closable
|
||||
@close="removeExtraArg(argId)"
|
||||
style="margin: 4px"
|
||||
>
|
||||
{{ getSpecNameById(argId) }} (ID: {{ argId }})
|
||||
</el-tag>
|
||||
</div> -->
|
||||
<el-empty v-if="extraSpecList.length === 0" description="所有参数已在参数配置中选择" :image-size="40" />
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="排序索引" prop="index">
|
||||
<el-input-number v-model="planForm.index" :min="0" style="width: 100%" />
|
||||
@@ -562,6 +681,37 @@
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 参数配置预览对话框 -->
|
||||
<el-dialog
|
||||
v-model="showArgsPreview"
|
||||
title="参数配置预览"
|
||||
width="500px"
|
||||
append-to-body
|
||||
>
|
||||
<div class="args-preview">
|
||||
<div class="preview-header">
|
||||
<span>已选择 {{ Object.keys(selectedArgs).filter(k => selectedArgs[k] !== undefined && selectedArgs[k] !== '').length }} 个参数</span>
|
||||
<el-tag :type="isArgsValid ? 'success' : 'warning'" size="small">
|
||||
{{ isArgsValid ? '配置有效' : '部分参数未选择' }}
|
||||
</el-tag>
|
||||
</div>
|
||||
<el-divider />
|
||||
<div class="preview-list">
|
||||
<div v-for="spec in planSpecList" :key="spec.id" class="preview-item">
|
||||
<span class="preview-label">{{ spec.name }}:</span>
|
||||
<span class="preview-value" :class="{ 'not-selected': !getSelectedValueDisplay(spec) }">
|
||||
{{ getSelectedValueDisplay(spec) || '未选择' }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<el-divider content-position="left">JSON 数据</el-divider>
|
||||
<pre class="json-preview">{{ formatArgsJsonPreview() }}</pre>
|
||||
</div>
|
||||
<template #footer>
|
||||
<el-button @click="showArgsPreview = false">关闭</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 商品分组选择器对话框 -->
|
||||
<el-dialog
|
||||
v-model="showGroupSelector"
|
||||
@@ -622,7 +772,7 @@
|
||||
import { ref, reactive, computed, onMounted, nextTick } from 'vue'
|
||||
import { getFileDetail } from '@/api/admin/file'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { Plus, Delete, Search, Refresh, Picture, ArrowRight, Loading } from '@element-plus/icons-vue'
|
||||
import { Plus, Delete, Search, Refresh, Picture, ArrowRight, Loading, View } from '@element-plus/icons-vue'
|
||||
import AvatarSelector from '@/components/admin/AvatarSelector.vue'
|
||||
import { getProductList, createProduct, updateProduct, deleteProduct, getProductGroupList,
|
||||
getProductTagList,
|
||||
@@ -1371,9 +1521,9 @@ const handleEditParamValue = (row) => {
|
||||
attr_id: row.id,
|
||||
attr_name: row.name,
|
||||
attr_value: row.value || '',
|
||||
attr_price: (row.price / 100).toFixed(2) || 0,
|
||||
attr_price: row.price || 0,
|
||||
index: row.index || 0,
|
||||
attr_range: row.range || 0,
|
||||
attr_range: row.phase || 0, // API返回的字段是 phase
|
||||
range_type: row.rangeType || 'equal'
|
||||
})
|
||||
}
|
||||
@@ -1414,7 +1564,7 @@ const submitParamValueForm = () => {
|
||||
if (currentParam.value.type === 'select') {
|
||||
submitData.attr_value = paramValueForm.attr_value
|
||||
}
|
||||
// number 类型添加范围参数
|
||||
// number 类型添加范围参数(提交用 attr_range,获取返回 phase)
|
||||
if (currentParam.value.type === 'number') {
|
||||
submitData.attr_range = Number(paramValueForm.attr_range)
|
||||
submitData.range_type = paramValueForm.range_type
|
||||
@@ -1456,6 +1606,7 @@ const planForm = reactive({
|
||||
note: '',
|
||||
args: '',
|
||||
extra_arg_ids: '',
|
||||
extra_arg_ids_array: [],
|
||||
index: 0,
|
||||
disable: false
|
||||
})
|
||||
@@ -1464,6 +1615,269 @@ const planFormRules = {
|
||||
name: [{ required: true, message: '请输入套餐名称', trigger: 'blur' }]
|
||||
}
|
||||
|
||||
// 套餐参数选择相关
|
||||
const planSpecList = ref([]) // 当前商品的参数列表
|
||||
const selectedArgIds = ref([]) // 选中的参数ID列表
|
||||
const selectedArgs = reactive({}) // 选中的参数值 { arg_id: value_id 或 value }
|
||||
const showArgsPreview = ref(false) // 显示参数预览对话框
|
||||
|
||||
// 额外参数相关
|
||||
const selectedExtraArgIds = ref([]) // 选中的额外参数ID列表
|
||||
|
||||
// 计算已选参数的spec列表
|
||||
const selectedArgSpecs = computed(() => {
|
||||
return planSpecList.value.filter(spec => selectedArgIds.value.includes(spec.id))
|
||||
})
|
||||
|
||||
// 计算额外参数列表(参数配置中未选择的参数)
|
||||
const extraSpecList = computed(() => {
|
||||
return planSpecList.value.filter(spec => !selectedArgIds.value.includes(spec.id))
|
||||
})
|
||||
|
||||
// 获取套餐表单用的参数列表
|
||||
const fetchPlanSpecList = async () => {
|
||||
if (!currentPlanProductId.value) return
|
||||
try {
|
||||
const res = await getProductParameterList({ good_id: currentPlanProductId.value })
|
||||
if (res.data.code === 200) {
|
||||
planSpecList.value = res.data.data || []
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取参数列表失败:', error)
|
||||
planSpecList.value = []
|
||||
}
|
||||
}
|
||||
|
||||
// 参数选择变化
|
||||
const onSelectedArgsChange = () => {
|
||||
// 清除未选中参数的值
|
||||
for (const key in selectedArgs) {
|
||||
if (!selectedArgIds.value.includes(Number(key))) {
|
||||
delete selectedArgs[key]
|
||||
}
|
||||
}
|
||||
// 同时从额外参数中移除已选的参数
|
||||
selectedExtraArgIds.value = selectedExtraArgIds.value.filter(
|
||||
id => !selectedArgIds.value.includes(id)
|
||||
)
|
||||
updateArgsJson()
|
||||
updateExtraArgIds()
|
||||
}
|
||||
|
||||
// 额外参数选择变化
|
||||
const onSelectedExtraArgsChange = () => {
|
||||
updateExtraArgIds()
|
||||
}
|
||||
|
||||
// 移除额外参数
|
||||
const removeExtraArg = (argId) => {
|
||||
selectedExtraArgIds.value = selectedExtraArgIds.value.filter(id => id !== argId)
|
||||
updateExtraArgIds()
|
||||
}
|
||||
|
||||
// 根据ID获取参数名称
|
||||
const getSpecNameById = (specId) => {
|
||||
const spec = planSpecList.value.find(s => s.id === specId)
|
||||
return spec ? spec.name : `参数${specId}`
|
||||
}
|
||||
|
||||
// 更新额外参数ID
|
||||
const updateExtraArgIds = () => {
|
||||
planForm.extra_arg_ids = selectedExtraArgIds.value.join(',')
|
||||
planForm.extra_arg_ids_array = [...selectedExtraArgIds.value]
|
||||
}
|
||||
|
||||
// 更新args JSON字符串
|
||||
// 格式:{ arg_id: 参数id, name: 参数名称, attr_id: 参数值id, value/number: 参数值 }
|
||||
const updateArgsJson = () => {
|
||||
const argsArray = []
|
||||
|
||||
// 只处理已选择的参数
|
||||
for (const specId of selectedArgIds.value) {
|
||||
const spec = planSpecList.value.find(s => s.id === specId)
|
||||
if (!spec) continue
|
||||
|
||||
const selectedValue = selectedArgs[spec.id]
|
||||
if (selectedValue === undefined || selectedValue === '') continue
|
||||
|
||||
if (spec.type === 'select') {
|
||||
// select 类型:找到选中的值对象
|
||||
const attrObj = spec.attrs?.find(a => a.id === selectedValue)
|
||||
if (attrObj) {
|
||||
argsArray.push({
|
||||
arg_id: spec.id,
|
||||
name: spec.name,
|
||||
attr_id: attrObj.id,
|
||||
value: attrObj.value || ''
|
||||
})
|
||||
}
|
||||
} else if (spec.type === 'number') {
|
||||
// number 类型:根据数值找到对应的价格区间ID
|
||||
const numValue = Number(selectedValue)
|
||||
const matchedAttr = findMatchingNumberAttr(spec, numValue)
|
||||
|
||||
argsArray.push({
|
||||
arg_id: spec.id,
|
||||
name: spec.name,
|
||||
attr_id: matchedAttr ? matchedAttr.id : 0,
|
||||
number: numValue
|
||||
})
|
||||
} else {
|
||||
// string 类型
|
||||
argsArray.push({
|
||||
arg_id: spec.id,
|
||||
name: spec.name,
|
||||
attr_id: 0,
|
||||
value: String(selectedValue)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
planForm.args = argsArray.length > 0 ? JSON.stringify(argsArray) : ''
|
||||
}
|
||||
|
||||
// 根据数值找到匹配的价格区间
|
||||
const findMatchingNumberAttr = (spec, numValue) => {
|
||||
if (!spec.attrs || spec.attrs.length === 0) return null
|
||||
|
||||
// 按 index 排序
|
||||
const sortedAttrs = [...spec.attrs].sort((a, b) => (a.index || 0) - (b.index || 0))
|
||||
|
||||
for (const attr of sortedAttrs) {
|
||||
const phase = attr.phase || 0
|
||||
const rangeType = attr.rangeType || 'before'
|
||||
|
||||
// rangeType: before 表示小于等于 phase
|
||||
// rangeType: after 表示大于等于 phase
|
||||
// rangeType: equal 表示等于 phase
|
||||
if (rangeType === 'before' && numValue <= phase) {
|
||||
return attr
|
||||
} else if (rangeType === 'after' && numValue >= phase) {
|
||||
return attr
|
||||
} else if (rangeType === 'equal' && numValue === phase) {
|
||||
return attr
|
||||
}
|
||||
}
|
||||
|
||||
// 如果没有匹配的,返回最后一个区间
|
||||
return sortedAttrs[sortedAttrs.length - 1]
|
||||
}
|
||||
|
||||
// 获取匹配的价格区间名称(用于模板显示)
|
||||
const getMatchedAttrName = (spec, numValue) => {
|
||||
const matchedAttr = findMatchingNumberAttr(spec, Number(numValue))
|
||||
if (matchedAttr) {
|
||||
const priceText = matchedAttr.price ? ` (+¥${(matchedAttr.price / 100).toFixed(2)})` : ''
|
||||
return `${matchedAttr.name}${priceText}`
|
||||
}
|
||||
return '无匹配区间'
|
||||
}
|
||||
|
||||
// 生成参数项的唯一ID(用于没有attrs的number和string类型)
|
||||
const generateArgId = (argId, value) => {
|
||||
// 使用参数ID和值的组合生成一个数字ID
|
||||
const valueHash = String(value).split('').reduce((acc, char) => acc + char.charCodeAt(0), 0)
|
||||
return argId * 10000 + (valueHash % 10000)
|
||||
}
|
||||
|
||||
// 更新额外参数JSON
|
||||
// 清空参数选择
|
||||
const clearArgsSelection = () => {
|
||||
selectedArgIds.value = []
|
||||
for (const key in selectedArgs) {
|
||||
delete selectedArgs[key]
|
||||
}
|
||||
selectedExtraArgIds.value = []
|
||||
planForm.args = ''
|
||||
planForm.extra_arg_ids = ''
|
||||
planForm.extra_arg_ids_array = []
|
||||
}
|
||||
|
||||
// 获取选中值的显示文本
|
||||
const getSelectedValueDisplay = (spec) => {
|
||||
const selectedValue = selectedArgs[spec.id]
|
||||
if (selectedValue === undefined || selectedValue === '') return null
|
||||
|
||||
if (spec.type === 'select') {
|
||||
const attrObj = spec.attrs?.find(a => a.id === selectedValue)
|
||||
return attrObj ? attrObj.name : null
|
||||
}
|
||||
return String(selectedValue)
|
||||
}
|
||||
|
||||
// 检查参数配置是否有效
|
||||
const isArgsValid = computed(() => {
|
||||
// 至少选择了一个参数
|
||||
return Object.keys(selectedArgs).some(k => selectedArgs[k] !== undefined && selectedArgs[k] !== '')
|
||||
})
|
||||
|
||||
// 格式化预览JSON
|
||||
const formatArgsJsonPreview = () => {
|
||||
if (!planForm.args) return '[]'
|
||||
try {
|
||||
return JSON.stringify(JSON.parse(planForm.args), null, 2)
|
||||
} catch {
|
||||
return planForm.args
|
||||
}
|
||||
}
|
||||
|
||||
// 从已有的args JSON初始化选择状态
|
||||
const initSelectedArgsFromJson = (argsJson, extraArgIds = []) => {
|
||||
// 清空现有选择
|
||||
clearArgsSelection()
|
||||
|
||||
// 解析 args 中包含的参数ID
|
||||
const argsParamIds = []
|
||||
|
||||
if (argsJson) {
|
||||
try {
|
||||
const argsArray = typeof argsJson === 'string' ? JSON.parse(argsJson) : argsJson
|
||||
if (Array.isArray(argsArray)) {
|
||||
for (const arg of argsArray) {
|
||||
// 通过 arg_id 找到对应的参数
|
||||
const spec = planSpecList.value.find(s => s.id === arg.arg_id)
|
||||
if (!spec) continue
|
||||
|
||||
// 添加到已选参数ID列表
|
||||
argsParamIds.push(spec.id)
|
||||
|
||||
if (spec.type === 'select') {
|
||||
// select 类型:优先使用 attr_id,兼容旧格式的 id
|
||||
if (arg.attr_id) {
|
||||
selectedArgs[spec.id] = arg.attr_id
|
||||
} else if (arg.id) {
|
||||
selectedArgs[spec.id] = arg.id
|
||||
} else {
|
||||
const attrObj = spec.attrs?.find(a => a.value === arg.value || a.name === arg.name)
|
||||
if (attrObj) {
|
||||
selectedArgs[spec.id] = attrObj.id
|
||||
}
|
||||
}
|
||||
} else if (spec.type === 'number') {
|
||||
// number 类型:优先使用 number 字段,兼容 value 字段
|
||||
selectedArgs[spec.id] = Number(arg.number !== undefined ? arg.number : arg.value)
|
||||
} else {
|
||||
selectedArgs[spec.id] = arg.value
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('解析args失败:', e)
|
||||
}
|
||||
}
|
||||
|
||||
// 设置已选参数ID列表
|
||||
selectedArgIds.value = argsParamIds
|
||||
|
||||
// 处理额外参数(排除已在args中的参数)
|
||||
if (extraArgIds && extraArgIds.length > 0) {
|
||||
selectedExtraArgIds.value = extraArgIds.filter(id => !argsParamIds.includes(id))
|
||||
}
|
||||
|
||||
// 根据选择状态重新生成 JSON(确保初始状态就有 JSON 展示)
|
||||
updateArgsJson()
|
||||
}
|
||||
|
||||
// 打开套餐管理
|
||||
const handlePlan = (row) => {
|
||||
currentPlanProductId.value = row.id
|
||||
@@ -1529,18 +1943,31 @@ const fetchPlanList = async () => {
|
||||
}
|
||||
|
||||
// 新增套餐
|
||||
const handleAddPlan = () => {
|
||||
const handleAddPlan = async () => {
|
||||
planFormType.value = 'add'
|
||||
planFormDialogVisible.value = true
|
||||
|
||||
// 先获取参数列表
|
||||
await fetchPlanSpecList()
|
||||
|
||||
// 清空选择状态
|
||||
clearArgsSelection()
|
||||
|
||||
// 默认选择所有参数
|
||||
selectedArgIds.value = planSpecList.value.map(spec => spec.id)
|
||||
|
||||
Object.assign(planForm, {
|
||||
plan_id: undefined,
|
||||
name: '',
|
||||
note: '',
|
||||
args: '',
|
||||
extra_arg_ids: '',
|
||||
extra_arg_ids_array: [],
|
||||
index: 0,
|
||||
disable: false
|
||||
})
|
||||
|
||||
planFormDialogVisible.value = true
|
||||
|
||||
nextTick(() => {
|
||||
planFormRef.value?.resetFields()
|
||||
})
|
||||
@@ -1549,32 +1976,39 @@ const handleAddPlan = () => {
|
||||
// 编辑套餐
|
||||
const handleEditPlan = async (row) => {
|
||||
planFormType.value = 'edit'
|
||||
|
||||
// 先获取参数列表
|
||||
await fetchPlanSpecList()
|
||||
|
||||
try {
|
||||
const res = await getProductPlanDetail({ good_id: String(currentPlanProductId.value), plan_id: String(row.id) })
|
||||
if (res.data.code === 200) {
|
||||
const data = res.data.data
|
||||
// 处理args字段:如果是字符串先解析,再格式化为漂亮的JSON
|
||||
let argsValue = ''
|
||||
if (data.args) {
|
||||
try {
|
||||
// 如果args是字符串,先解析为对象
|
||||
const argsObj = typeof data.args === 'string' ? JSON.parse(data.args) : data.args
|
||||
// 格式化为漂亮的JSON(带缩进)
|
||||
argsValue = JSON.stringify(argsObj, null, 2)
|
||||
} catch (e) {
|
||||
// 解析失败则保持原值
|
||||
argsValue = data.args
|
||||
|
||||
// 处理 extra_arg_ids
|
||||
let extraArgIdsArray = []
|
||||
if (data.extraArgIds) {
|
||||
if (Array.isArray(data.extraArgIds)) {
|
||||
extraArgIdsArray = data.extraArgIds
|
||||
} else if (typeof data.extraArgIds === 'string') {
|
||||
extraArgIdsArray = data.extraArgIds.split(',').filter(Boolean).map(Number)
|
||||
}
|
||||
}
|
||||
|
||||
Object.assign(planForm, {
|
||||
plan_id: data.id,
|
||||
name: data.name || '',
|
||||
note: data.note || '',
|
||||
args: argsValue,
|
||||
extra_arg_ids: data.extraArgIds ? data.extraArgIds.join(',') : '',
|
||||
args: data.args || '',
|
||||
extra_arg_ids: extraArgIdsArray.join(','),
|
||||
extra_arg_ids_array: extraArgIdsArray,
|
||||
index: data.index || 0,
|
||||
disable: data.disable || false
|
||||
})
|
||||
|
||||
// 从已有的args初始化选择状态(包括额外参数)
|
||||
initSelectedArgsFromJson(data.args, extraArgIdsArray)
|
||||
|
||||
planFormDialogVisible.value = true
|
||||
}
|
||||
} catch (error) {
|
||||
@@ -1914,5 +2348,149 @@ const submitPlanForm = () => {
|
||||
max-height: 450px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* 参数配置选择器样式 */
|
||||
.args-config-container {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.args-selector {
|
||||
border: 1px solid #e4e7ed;
|
||||
border-radius: 4px;
|
||||
padding: 12px;
|
||||
background: #fafafa;
|
||||
max-height: 300px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.spec-item {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
padding: 10px 0;
|
||||
border-bottom: 1px dashed #e4e7ed;
|
||||
transition: opacity 0.2s;
|
||||
}
|
||||
|
||||
.spec-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.spec-label {
|
||||
width: 100px;
|
||||
flex-shrink: 0;
|
||||
font-weight: 500;
|
||||
color: #606266;
|
||||
padding-top: 4px;
|
||||
}
|
||||
|
||||
/* 参数选择下拉行 */
|
||||
.args-select-row {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
/* 额外参数展示 */
|
||||
.extra-args-display {
|
||||
margin-top: 8px;
|
||||
padding: 8px;
|
||||
background: #f5f7fa;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.spec-values {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.spec-values :deep(.el-radio-group) {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.spec-values :deep(.el-radio-button__inner) {
|
||||
padding: 6px 12px;
|
||||
}
|
||||
|
||||
.number-input-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.number-range {
|
||||
color: #909399;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.matched-attr-info {
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
.args-actions {
|
||||
margin-top: 12px;
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
/* 参数预览样式 */
|
||||
.args-preview {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.preview-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.preview-list {
|
||||
max-height: 200px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.preview-item {
|
||||
display: flex;
|
||||
padding: 8px 0;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
}
|
||||
|
||||
.preview-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.preview-label {
|
||||
width: 120px;
|
||||
flex-shrink: 0;
|
||||
color: #606266;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.preview-value {
|
||||
color: #409eff;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.preview-value.not-selected {
|
||||
color: #c0c4cc;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.json-preview {
|
||||
background: #f5f7fa;
|
||||
border: 1px solid #e4e7ed;
|
||||
border-radius: 4px;
|
||||
padding: 12px;
|
||||
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
|
||||
font-size: 12px;
|
||||
color: #606266;
|
||||
max-height: 200px;
|
||||
overflow: auto;
|
||||
white-space: pre-wrap;
|
||||
word-break: break-all;
|
||||
margin: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user