|
@@ -19,6 +19,7 @@
|
|
|
<el-option label="虚拟商品" value="virtual" />
|
|
<el-option label="虚拟商品" value="virtual" />
|
|
|
<el-option label="优惠券" value="coupon" />
|
|
<el-option label="优惠券" value="coupon" />
|
|
|
<el-option label="测评商品" value="assessment" />
|
|
<el-option label="测评商品" value="assessment" />
|
|
|
|
|
+ <el-option label="套餐" value="bundle" />
|
|
|
</el-select>
|
|
</el-select>
|
|
|
</el-form-item>
|
|
</el-form-item>
|
|
|
|
|
|
|
@@ -53,6 +54,25 @@
|
|
|
</el-row>
|
|
</el-row>
|
|
|
</template>
|
|
</template>
|
|
|
|
|
|
|
|
|
|
+ <!-- 套餐商品扩展信息 -->
|
|
|
|
|
+ <template v-if="form.productType === 'bundle'">
|
|
|
|
|
+ <el-divider content-position="left">套餐组成</el-divider>
|
|
|
|
|
+ <el-form-item label="组成商品">
|
|
|
|
|
+ <div v-for="(item, idx) in bundleItems" :key="'bi' + idx" style="display:flex; align-items:center; margin-bottom:8px; gap:8px; flex-wrap:wrap;">
|
|
|
|
|
+ <el-select v-model="item.childProductId" filterable remote placeholder="搜索子商品" :remote-method="(q) => searchBundleProduct(q, idx)" style="width:220px;" @change="(pid) => onBundleProductChange(pid, idx)">
|
|
|
|
|
+ <el-option v-for="p in item.productOptions" :key="p.id" :label="(p.name || 'ID:' + p.id) + ' (库存:' + (p.stock || 0) + ')'" :value="p.id" />
|
|
|
|
|
+ </el-select>
|
|
|
|
|
+ <el-select v-if="item.skuOptions.length" v-model="item.childSkuId" placeholder="选择规格" clearable style="width:160px;">
|
|
|
|
|
+ <el-option v-for="s in item.skuOptions" :key="s.id" :label="(s.specs || '默认') + ' (库存:' + (s.stock || 0) + ')'" :value="s.id" />
|
|
|
|
|
+ </el-select>
|
|
|
|
|
+ <el-input-number v-model="item.quantity" :min="1" :precision="0" size="small" style="width:110px;" />
|
|
|
|
|
+ <el-button type="danger" size="mini" @click="removeBundleItem(idx)">删除</el-button>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <el-button type="primary" size="mini" plain @click="addBundleItem">+ 添加子商品</el-button>
|
|
|
|
|
+ <div style="margin-top:8px; font-size:12px; color:#999;">套餐出库时自动完成所有组成商品出库(数量 × 套餐数量)</div>
|
|
|
|
|
+ </el-form-item>
|
|
|
|
|
+ </template>
|
|
|
|
|
+
|
|
|
<!-- 关联成长档案 -->
|
|
<!-- 关联成长档案 -->
|
|
|
<el-divider content-position="left">关联成长档案</el-divider>
|
|
<el-divider content-position="left">关联成长档案</el-divider>
|
|
|
<el-form-item label="关联成长档案">
|
|
<el-form-item label="关联成长档案">
|
|
@@ -293,7 +313,7 @@
|
|
|
</template>
|
|
</template>
|
|
|
|
|
|
|
|
<script>
|
|
<script>
|
|
|
-import { getProduct, createProduct, updateProduct, listAllSupplySystems, getPredefinedPurchaseFields, getProductPurchaseFields, saveProductPurchaseFields, getMySupplySystem, saveProductGiftRule, listProductGiftRules, listMembershipLevels, getGrowthArchiveProduct, saveGrowthArchiveProduct, listDeliveryServicePersons, saveDeliveryServicePersons, listDeliveryOnlineSlots, saveDeliveryOnlineSlots } from '@/api/admin'
|
|
|
|
|
|
|
+import { getProduct, createProduct, updateProduct, listAllSupplySystems, getPredefinedPurchaseFields, getProductPurchaseFields, saveProductPurchaseFields, getMySupplySystem, saveProductGiftRule, listProductGiftRules, listMembershipLevels, getGrowthArchiveProduct, saveGrowthArchiveProduct, listDeliveryServicePersons, saveDeliveryServicePersons, listDeliveryOnlineSlots, saveDeliveryOnlineSlots, getProductList, getProductSkuList, saveBundleItems, getBundleItems } from '@/api/admin'
|
|
|
import { saveDimensionWeights, getDimensionWeights } from '@/api/dimension-weight'
|
|
import { saveDimensionWeights, getDimensionWeights } from '@/api/dimension-weight'
|
|
|
import DimensionWeightPicker from '@/components/DimensionWeightPicker.vue'
|
|
import DimensionWeightPicker from '@/components/DimensionWeightPicker.vue'
|
|
|
import ProductSkuEditor from './components/ProductSkuEditor.vue'
|
|
import ProductSkuEditor from './components/ProductSkuEditor.vue'
|
|
@@ -329,6 +349,7 @@ export default {
|
|
|
guideScope: 'all',
|
|
guideScope: 'all',
|
|
|
sortOrder: 0
|
|
sortOrder: 0
|
|
|
},
|
|
},
|
|
|
|
|
+ bundleItems: [], // 套餐组成: [{childProductId, childSkuId, quantity, productOptions:[], skuOptions:[]}]
|
|
|
servicePersons: [], // 线上服务者(deliveryMethod=4): [{userId,name,title,intro,avatar,price,originalPrice,slots:[{startTime,endTime,maxCapacity}]}]
|
|
servicePersons: [], // 线上服务者(deliveryMethod=4): [{userId,name,title,intro,avatar,price,originalPrice,slots:[{startTime,endTime,maxCapacity}]}]
|
|
|
onlineSlots: [], // 单人线上时段(deliveryMethod=5): [{startTime,endTime,maxCapacity}]
|
|
onlineSlots: [], // 单人线上时段(deliveryMethod=5): [{startTime,endTime,maxCapacity}]
|
|
|
growthArchive: {
|
|
growthArchive: {
|
|
@@ -373,8 +394,73 @@ export default {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+}
|
|
|
|
|
+ },
|
|
|
|
|
+ addBundleItem() {
|
|
|
|
|
+ this.bundleItems.push({
|
|
|
|
|
+ childProductId: null,
|
|
|
|
|
+ childSkuId: null,
|
|
|
|
|
+ quantity: 1,
|
|
|
|
|
+ productOptions: [],
|
|
|
|
|
+ skuOptions: []
|
|
|
|
|
+ })
|
|
|
|
|
+ },
|
|
|
|
|
+ removeBundleItem(idx) {
|
|
|
|
|
+ this.bundleItems.splice(idx, 1)
|
|
|
|
|
+ },
|
|
|
|
|
+ async searchBundleProduct(query, idx) {
|
|
|
|
|
+ if (!query || query.length < 1) return
|
|
|
|
|
+ try {
|
|
|
|
|
+ var res = await getProductList({ keyword: query, page: 1, size: 20 })
|
|
|
|
|
+ if (res.code === 200 && res.data && Array.isArray(res.data.records)) {
|
|
|
|
|
+ this.bundleItems[idx].productOptions = res.data.records
|
|
|
}
|
|
}
|
|
|
- },
|
|
|
|
|
|
|
+ } catch (e) { /* ignore */ }
|
|
|
|
|
+ },
|
|
|
|
|
+ async onBundleProductChange(productId, idx) {
|
|
|
|
|
+ var item = this.bundleItems[idx]
|
|
|
|
|
+ item.childSkuId = null
|
|
|
|
|
+ item.skuOptions = []
|
|
|
|
|
+ if (!productId) return
|
|
|
|
|
+ try {
|
|
|
|
|
+ var res = await getProductSkuList(productId)
|
|
|
|
|
+ if (res.code === 200 && Array.isArray(res.data)) {
|
|
|
|
|
+ item.skuOptions = res.data
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (e) { /* ignore */ }
|
|
|
|
|
+ },
|
|
|
|
|
+ buildBundleItemPayload() {
|
|
|
|
|
+ return this.bundleItems
|
|
|
|
|
+ .filter(function(b) { return b.childProductId })
|
|
|
|
|
+ .map(function(b) {
|
|
|
|
|
+ return {
|
|
|
|
|
+ childProductId: b.childProductId,
|
|
|
|
|
+ childSkuId: b.childSkuId || null,
|
|
|
|
|
+ quantity: b.quantity || 1
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
|
|
+ },
|
|
|
|
|
+ async loadBundleItems(productId) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ var res = await getBundleItems(productId)
|
|
|
|
|
+ if (res.code === 200 && Array.isArray(res.data)) {
|
|
|
|
|
+ this.bundleItems = res.data.map(function(b) {
|
|
|
|
|
+ return {
|
|
|
|
|
+ childProductId: b.childProductId,
|
|
|
|
|
+ childSkuId: b.childSkuId || null,
|
|
|
|
|
+ quantity: b.quantity || 1,
|
|
|
|
|
+ productOptions: [],
|
|
|
|
|
+ skuOptions: []
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
|
|
+ this.bundleItems.forEach(function(item, idx) {
|
|
|
|
|
+ if (item.childProductId) {
|
|
|
|
|
+ this.onBundleProductChange(item.childProductId, idx)
|
|
|
|
|
+ }
|
|
|
|
|
+ }, this)
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (e) { /* ignore */ }
|
|
|
|
|
+ },
|
|
|
toolbarConfig: {},
|
|
toolbarConfig: {},
|
|
|
editorInstance: null
|
|
editorInstance: null
|
|
|
}
|
|
}
|
|
@@ -493,6 +579,10 @@ export default {
|
|
|
this.loadGrowthArchive(p.id)
|
|
this.loadGrowthArchive(p.id)
|
|
|
// Load delivery config (service persons / online slots)
|
|
// Load delivery config (service persons / online slots)
|
|
|
this.loadDeliveryConfig(p.id)
|
|
this.loadDeliveryConfig(p.id)
|
|
|
|
|
+ // Load bundle items config(套餐商品)
|
|
|
|
|
+ if (p.productType === 'bundle') {
|
|
|
|
|
+ this.loadBundleItems(p.id)
|
|
|
|
|
+ }
|
|
|
// v-model 已绑定 form.description,editor 内容自动更新
|
|
// v-model 已绑定 form.description,editor 内容自动更新
|
|
|
}
|
|
}
|
|
|
} catch (e) {
|
|
} catch (e) {
|
|
@@ -806,6 +896,16 @@ async loadGiftRule(productId) {
|
|
|
console.warn('保存线上服务配置失败', e)
|
|
console.warn('保存线上服务配置失败', e)
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+ // Save bundle items config(套餐商品组成)
|
|
|
|
|
+ if (productId) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ var bundlePayload = this.buildBundleItemPayload()
|
|
|
|
|
+ await saveBundleItems(productId, bundlePayload)
|
|
|
|
|
+ } catch (e) {
|
|
|
|
|
+ this.$message.error('保存套餐组成失败')
|
|
|
|
|
+ console.warn('保存套餐组成失败', e)
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
this.$message.success(this.isEdit ? '保存成功' : '创建成功')
|
|
this.$message.success(this.isEdit ? '保存成功' : '创建成功')
|
|
|
this.$router.push('/product-manage')
|
|
this.$router.push('/product-manage')
|
|
|
} else {
|
|
} else {
|