1
This commit is contained in:
@@ -10,5 +10,5 @@ VUE_APP_BASE_API = ''
|
||||
# 路由懒加载
|
||||
VUE_CLI_BABEL_TRANSPILE_MODULES = true
|
||||
|
||||
VUE_APP_BASE_API = 'http://134.175.126.60:30313'
|
||||
VUE_APP_BASE_API = 'http://127.0.0.1:30313'
|
||||
port = 8888
|
||||
|
||||
@@ -8,3 +8,71 @@ export function generatePromotionContent(data) {
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 创建商品(基于转链生成的文案与图片)
|
||||
export function createProductByPromotion(data) {
|
||||
return request({
|
||||
url: '/erp/product/createByPromotion',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 地区下拉
|
||||
export function getProvinces() {
|
||||
return request({
|
||||
url: '/erp/region/provinces',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
export function getCities(provId) {
|
||||
return request({
|
||||
url: '/erp/region/cities',
|
||||
method: 'get',
|
||||
params: { provId }
|
||||
})
|
||||
}
|
||||
|
||||
export function getAreas(provId, cityId) {
|
||||
return request({
|
||||
url: '/erp/region/areas',
|
||||
method: 'get',
|
||||
params: { provId, cityId }
|
||||
})
|
||||
}
|
||||
|
||||
// 类目下拉
|
||||
export function getCategories(params) {
|
||||
return request({
|
||||
url: '/erp/product/categories',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
// 会员名下拉
|
||||
export function getUsernames(params) {
|
||||
return request({
|
||||
url: '/erp/product/usernames',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
// ERP 账号下拉(备用)
|
||||
export function getERPAccounts() {
|
||||
return request({
|
||||
url: '/erp/product/ERPAccount',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 属性下拉
|
||||
export function getProperties(params) {
|
||||
return request({
|
||||
url: '/erp/product/pv',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
@@ -69,6 +69,7 @@
|
||||
/>
|
||||
<div style="margin-top: 10px;">
|
||||
<el-button type="success" @click="handleCopyText(wenan.content || '')">复制此版本</el-button>
|
||||
<el-button type="primary" style="margin-left: 8px;" @click="openPublish(product, productIndex)">发品</el-button>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
@@ -95,6 +96,11 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 发品操作 -->
|
||||
<div style="margin-top: 10px;">
|
||||
<el-button type="primary" @click="openPublish(product, productIndex)">发品</el-button>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
@@ -115,18 +121,138 @@
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<!-- 发品对话框 -->
|
||||
<el-dialog title="发品" :visible.sync="publishDialog.visible" width="1200px" :close-on-click-modal="false" :close-on-press-escape="false" :destroy-on-close="false" append-to-body>
|
||||
<el-form :model="publishDialog.form" :rules="publishDialog.rules" ref="publishForm" label-width="110px">
|
||||
<el-form-item label="文案版本" v-if="publishDialog.wenanOptions && publishDialog.wenanOptions.length > 0">
|
||||
<el-select v-model="publishDialog.form.wenanIndex" placeholder="选择文案版本" @change="onWenanChange" style="width:100%">
|
||||
<el-option v-for="(opt, idx) in publishDialog.wenanOptions" :key="idx" :label="opt.label" :value="idx" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="闲管家账号">
|
||||
<el-select v-model="publishDialog.form.appid" filterable placeholder="选择ERP应用" :loading="erpAccountLoading" @change="onAppidChange">
|
||||
<el-option v-for="a in erpAccountsOptions" :key="a.value" :label="a.label" :value="a.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="标题" prop="title">
|
||||
<el-input v-model="publishDialog.form.title" maxlength="60" show-word-limit />
|
||||
</el-form-item>
|
||||
<el-form-item label="文案内容" prop="content">
|
||||
<el-input type="textarea" :rows="6" v-model="publishDialog.form.content" />
|
||||
</el-form-item>
|
||||
<el-form-item label="选择图片" v-if="publishDialog.productImages && publishDialog.productImages.length">
|
||||
<div class="img-grid">
|
||||
<div class="img-item" v-for="(img, idx) in publishDialog.productImages" :key="idx">
|
||||
<img :src="img.url" :alt="`图片${idx+1}`" @click="handlePreviewImage(img.url)" />
|
||||
<div class="img-actions">
|
||||
<el-checkbox v-model="img.selected">使用</el-checkbox>
|
||||
<el-button type="text" size="mini" @click="handleCopyImageUrl(img.url)">复制</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="margin-top:8px;">
|
||||
<el-button size="mini" @click="selectAllImages(true)">全选</el-button>
|
||||
<el-button size="mini" @click="selectAllImages(false)">全不选</el-button>
|
||||
<el-button size="mini" @click="invertSelection">反选</el-button>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="额外图片链接">
|
||||
<el-input type="textarea" :rows="3" v-model="publishDialog.form.extraImagesText" placeholder="每行一条图片URL" />
|
||||
</el-form-item>
|
||||
<el-form-item label="白底图">
|
||||
<el-input v-model="publishDialog.form.whiteImages" placeholder="可选,图片URL" />
|
||||
</el-form-item>
|
||||
<el-form-item label="服务项">
|
||||
<el-select v-model="publishDialog.form.serviceSupport" multiple collapse-tags placeholder="可多选">
|
||||
<el-option v-for="opt in serviceSupportOptions" :key="opt.value" :label="opt.label" :value="opt.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="会员名" prop="userName">
|
||||
<el-select v-model="publishDialog.form.userName" filterable placeholder="选择会员名" :loading="userNameLoading">
|
||||
<el-option v-for="u in userNameOptions" :key="u.value" :label="u.label" :value="u.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="省/市/区" required>
|
||||
<div style="display:flex; gap:8px; width:100%">
|
||||
<el-select v-model.number="publishDialog.form.province" placeholder="选择省" style="flex:1" filterable @change="onProvinceChange">
|
||||
<el-option v-for="p in regionOptions.provinces" :key="p.value" :label="p.label" :value="p.value" />
|
||||
</el-select>
|
||||
<el-select v-model.number="publishDialog.form.city" placeholder="选择市" style="flex:1" filterable :disabled="!publishDialog.form.province" @change="onCityChange">
|
||||
<el-option v-for="c in regionOptions.cities" :key="c.value" :label="c.label" :value="c.value" />
|
||||
</el-select>
|
||||
<el-select v-model.number="publishDialog.form.district" placeholder="选择区" style="flex:1" filterable :disabled="!publishDialog.form.city">
|
||||
<el-option v-for="a in regionOptions.areas" :key="a.value" :label="a.label" :value="a.value" />
|
||||
</el-select>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="价格(元)" prop="price">
|
||||
<el-input v-model.number="publishDialog.form.price" type="number" min="0.01" step="0.01" />
|
||||
</el-form-item>
|
||||
<el-form-item label="原价(元)">
|
||||
<el-input v-model.number="publishDialog.form.originalPrice" type="number" min="0" step="0.01" />
|
||||
</el-form-item>
|
||||
<el-form-item label="运费(元)" prop="expressFee">
|
||||
<el-input v-model.number="publishDialog.form.expressFee" type="number" min="0" step="0.01" />
|
||||
</el-form-item>
|
||||
<el-form-item label="库存" prop="stock">
|
||||
<el-input v-model.number="publishDialog.form.stock" type="number" min="1" />
|
||||
</el-form-item>
|
||||
<el-form-item label="商家编码">
|
||||
<el-input v-model="publishDialog.form.outerId" maxlength="64" />
|
||||
</el-form-item>
|
||||
<el-form-item label="商品类型" prop="itemBizType">
|
||||
<el-select v-model.number="publishDialog.form.itemBizType" filterable @change="onItemBizTypeChange">
|
||||
<el-option v-for="opt in itemBizTypeOptions" :key="opt.value" :label="opt.label" :value="opt.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="行业类型" prop="spBizType">
|
||||
<el-select v-model.number="publishDialog.form.spBizType" filterable @change="onSpBizTypeChange">
|
||||
<el-option v-for="opt in spBizTypeOptions" :key="opt.value" :label="opt.label" :value="opt.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="类目ID" prop="channelCatId">
|
||||
<el-select v-model="publishDialog.form.channelCatId" filterable placeholder="请选择类目" :disabled="!categoryOptions.length" :loading="categoryLoading" @change="loadProperties">
|
||||
<el-option v-for="c in categoryOptions" :key="c.value" :label="c.label" :value="c.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="商品属性">
|
||||
<div v-if="pvOptions.length" style="display:flex; flex-direction:column; gap:8px;">
|
||||
<div v-for="(p, pi) in pvOptions" :key="p.propertyId" style="display:flex; gap:8px; align-items:center;">
|
||||
<span style="width:90px; text-align:right; color:#666;">{{ p.propertyName }}:</span>
|
||||
<el-select v-model="selectedPv[p.propertyId]" clearable filterable placeholder="请选择" style="flex:1" @change="onPvChange">
|
||||
<el-option v-for="v in p.values" :key="v.valueId" :label="v.valueName" :value="v.valueId" />
|
||||
</el-select>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else style="color:#999;">无属性或请选择类型和类目后加载</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="成色">
|
||||
<el-select v-model.number="publishDialog.form.stuffStatus" clearable filterable placeholder="可选">
|
||||
<el-option v-for="opt in stuffStatusOptions" :key="opt.value" :label="opt.label" :value="opt.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="属性JSON">
|
||||
<el-input type="textarea" :rows="3" v-model="publishDialog.form.channelPvJson" placeholder='示例: [{"property_id":"p","property_name":"颜色","value_id":"v","value_name":"红"}]' />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="publishDialog.visible=false">取 消</el-button>
|
||||
<el-button type="primary" :loading="publishDialog.loading" @click="submitPublish">确 认</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { generatePromotionContent } from "@/api/system/jdorder";
|
||||
import { generatePromotionContent, createProductByPromotion, getProvinces, getCities, getAreas, getCategories, getUsernames, getERPAccounts, getProperties } from "@/api/system/jdorder";
|
||||
|
||||
export default {
|
||||
name: "Jdorder",
|
||||
data() {
|
||||
return {
|
||||
form: {
|
||||
inputContent: ""
|
||||
inputContent: "示例 https://u.jd.com/YDy2OHn"
|
||||
},
|
||||
loading: false,
|
||||
result: "",
|
||||
@@ -134,9 +260,131 @@ export default {
|
||||
// 当前选中的商品
|
||||
activeProductTab: 0,
|
||||
// 每个商品的文案标签页状态
|
||||
activeWenanTab: {}
|
||||
activeWenanTab: {},
|
||||
publishDialog: {
|
||||
visible: false,
|
||||
loading: false,
|
||||
wenanOptions: [],
|
||||
productImages: [],
|
||||
form: {
|
||||
appid: '',
|
||||
userName: "",
|
||||
province: 440000,
|
||||
city: 440400,
|
||||
district: 440402,
|
||||
title: "",
|
||||
content: "",
|
||||
wenanIndex: 0,
|
||||
extraImagesText: "",
|
||||
whiteImages: "",
|
||||
serviceSupport: ['NFR'],
|
||||
price: null,
|
||||
originalPrice: null,
|
||||
expressFee: 0,
|
||||
stock: 999,
|
||||
outerId: "",
|
||||
itemBizType: 2,
|
||||
spBizType: 3,
|
||||
channelCatId: "",
|
||||
stuffStatus: 100,
|
||||
channelPvJson: ""
|
||||
},
|
||||
rules: {
|
||||
title: [{ required: true, message: '请输入标题', trigger: 'blur' }],
|
||||
content: [{ required: true, message: '请输入文案内容', trigger: 'blur' }],
|
||||
userName: [{ required: true, message: '请输入闲鱼会员名', trigger: 'blur' }],
|
||||
price: [{ required: true, message: '请输入价格(分)', trigger: 'blur' }],
|
||||
expressFee: [{ required: true, message: '请输入运费(分)', trigger: 'blur' }],
|
||||
stock: [{ required: true, message: '请输入库存', trigger: 'blur' }],
|
||||
itemBizType: [{ required: true, message: '请选择商品类型', trigger: 'change' }],
|
||||
spBizType: [{ required: true, message: '请选择行业类型', trigger: 'change' }],
|
||||
channelCatId: [{ required: true, message: '请输入类目ID', trigger: 'blur' }]
|
||||
}
|
||||
},
|
||||
regionOptions: {
|
||||
provinces: [],
|
||||
cities: [],
|
||||
areas: []
|
||||
},
|
||||
categoryOptions: [],
|
||||
categoryLoading: false,
|
||||
userNameOptions: [],
|
||||
userNameLoading: false,
|
||||
erpAccountsOptions: [],
|
||||
erpAccountLoading: false,
|
||||
pvOptions: [],
|
||||
selectedPv: {},
|
||||
itemBizTypeOptions: [
|
||||
{ label: '普通商品', value: 2 },
|
||||
{ label: '已验货', value: 0 },
|
||||
{ label: '验货宝', value: 10 },
|
||||
{ label: '闲鱼优品', value: 19 },
|
||||
{ label: '闲鱼特卖', value: 24 },
|
||||
{ label: '品牌捡漏', value: 26 }
|
||||
],
|
||||
spBizTypeOptions: [
|
||||
{ label: '手机', value: 1 },
|
||||
{ label: '时尚', value: 2 },
|
||||
{ label: '家电', value: 3 },
|
||||
{ label: '乐器', value: 8 },
|
||||
{ label: '数码3C', value: 9 },
|
||||
{ label: '奢品', value: 16 },
|
||||
{ label: '母婴', value: 17 },
|
||||
{ label: '美妆', value: 18 },
|
||||
{ label: '珠宝', value: 19 },
|
||||
{ label: '游戏', value: 20 },
|
||||
{ label: '家居', value: 21 },
|
||||
{ label: '虚拟', value: 22 },
|
||||
{ label: '图书', value: 24 },
|
||||
{ label: '食品', value: 27 },
|
||||
{ label: '玩具', value: 28 },
|
||||
{ label: '其他', value: 99 }
|
||||
],
|
||||
stuffStatusOptions: [
|
||||
{ label: '不传', value: null },
|
||||
{ label: '全新', value: 100 },
|
||||
{ label: '99新', value: 99 },
|
||||
{ label: '95新', value: 95 },
|
||||
{ label: '9成新', value: 90 },
|
||||
{ label: '8成新', value: 80 },
|
||||
{ label: '7成新', value: 70 },
|
||||
{ label: '6成新', value: 60 },
|
||||
{ label: '5成新', value: 50 }
|
||||
],
|
||||
serviceSupportOptions: [
|
||||
{ label: '七天无理由退货', value: 'SDR' },
|
||||
{ label: '描述不符包邮退', value: 'NFR' },
|
||||
{ label: '描述不符全额退(虚拟)', value: 'VNR' },
|
||||
{ label: '10分钟极速发货(虚拟)', value: 'FD_10MS' },
|
||||
{ label: '24小时极速发货', value: 'FD_24HS' },
|
||||
{ label: '48小时极速发货', value: 'FD_48HS' },
|
||||
{ label: '正品保障', value: 'FD_GPA' }
|
||||
]
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
// 页面加载即预拉省份与类目下拉,避免弹窗时再等待
|
||||
this.loadProvinces();
|
||||
this.loadERPAccounts();
|
||||
this.loadCategories();
|
||||
this.loadUsernames();
|
||||
},
|
||||
watch: {
|
||||
'publishDialog.form.itemBizType'(val) {
|
||||
// 冗余联动,防止@change未触发的情况
|
||||
this.onItemBizTypeChange();
|
||||
},
|
||||
'publishDialog.form.spBizType'(val) {
|
||||
this.onSpBizTypeChange();
|
||||
},
|
||||
'publishDialog.form.appid'(val) {
|
||||
this.onAppidChange();
|
||||
},
|
||||
'publishDialog.form.channelCatId'(val) {
|
||||
// 兜底:类目变更(包括编程方式设置)时,自动拉取属性
|
||||
this.loadProperties();
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleGenerate() {
|
||||
if (!this.form.inputContent.trim()) {
|
||||
@@ -260,6 +508,277 @@ export default {
|
||||
|
||||
handlePreviewImage(imageUrl) {
|
||||
window.open(imageUrl, '_blank');
|
||||
},
|
||||
|
||||
openPublish(product, productIndex) {
|
||||
const wenanIndex = this.activeWenanTab[productIndex] || 0;
|
||||
const wenanContent = product && product.wenan && product.wenan[wenanIndex] ? (product.wenan[wenanIndex].content || '') : '';
|
||||
const images = Array.isArray(product.images) ? product.images : [];
|
||||
const wenanOptions = Array.isArray(product.wenan) ? product.wenan.map((w, i) => ({ label: w.type || `版本${i+1}`, content: w.content || '' })) : [];
|
||||
this.publishDialog.wenanOptions = wenanOptions;
|
||||
this.publishDialog.form = Object.assign({}, this.publishDialog.form, {
|
||||
title: product.skuName || '',
|
||||
content: wenanContent,
|
||||
wenanIndex: wenanIndex,
|
||||
extraImagesText: '',
|
||||
whiteImages: '',
|
||||
serviceSupport: this.publishDialog.form.serviceSupport,
|
||||
userName: '',
|
||||
province: this.publishDialog.form.province,
|
||||
city: this.publishDialog.form.city,
|
||||
district: this.publishDialog.form.district,
|
||||
price: null,
|
||||
originalPrice: null,
|
||||
expressFee: 0,
|
||||
stock: this.publishDialog.form.stock,
|
||||
outerId: '',
|
||||
itemBizType: this.publishDialog.form.itemBizType,
|
||||
spBizType: this.publishDialog.form.spBizType,
|
||||
channelCatId: '',
|
||||
stuffStatus: this.publishDialog.form.stuffStatus,
|
||||
channelPvJson: ''
|
||||
});
|
||||
// 预填原价(元)
|
||||
const guessed = this.guessYuanPrice(product);
|
||||
if (guessed != null) {
|
||||
this.publishDialog.form.originalPrice = Number(Number(guessed).toFixed(2));
|
||||
}
|
||||
this.publishDialog.productImages = images.map(u => ({ url: u, selected: true }));
|
||||
this.publishDialog.visible = true;
|
||||
this.$nextTick(() => this.$refs.publishForm && this.$refs.publishForm.clearValidate());
|
||||
// 载入省份
|
||||
this.loadProvinces();
|
||||
},
|
||||
|
||||
onWenanChange(val) {
|
||||
if (this.publishDialog.wenanOptions && this.publishDialog.wenanOptions[val]) {
|
||||
this.publishDialog.form.content = this.publishDialog.wenanOptions[val].content || '';
|
||||
}
|
||||
},
|
||||
|
||||
selectAllImages(flag) {
|
||||
(this.publishDialog.productImages || []).forEach(it => { it.selected = !!flag; });
|
||||
},
|
||||
invertSelection() {
|
||||
(this.publishDialog.productImages || []).forEach(it => { it.selected = !it.selected; });
|
||||
},
|
||||
|
||||
// 从解析到的商品信息中推测原价(元) —— 后端已保证返回“元”,不再做分到元换算
|
||||
guessYuanPrice(product) {
|
||||
// 常见字段尝试:price、oriPrice、originPrice、jdPrice、marketPrice 等(单位可能为元)
|
||||
const candidates = [
|
||||
product && product.price,
|
||||
product && product.oriPrice,
|
||||
product && product.originPrice,
|
||||
product && product.jdPrice,
|
||||
product && product.marketPrice,
|
||||
product && product.opPrice,
|
||||
].filter(v => v != null);
|
||||
for (const v of candidates) {
|
||||
const n = Number(v);
|
||||
if (!Number.isNaN(n) && n > 0) {
|
||||
return n;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
async loadProvinces(echo = true) {
|
||||
try {
|
||||
const res = await getProvinces();
|
||||
if (res.code === 200) this.regionOptions.provinces = res.data || []; else this.$modal.msgError(res.msg || '加载省份失败');
|
||||
} catch (e) { this.$modal.msgError('加载省份失败'); }
|
||||
if (echo && this.publishDialog.form.province) {
|
||||
await this.loadCities(this.publishDialog.form.province, true);
|
||||
} else {
|
||||
this.regionOptions.cities = []; this.regionOptions.areas = [];
|
||||
this.publishDialog.form.city = null; this.publishDialog.form.district = null;
|
||||
}
|
||||
},
|
||||
async onProvinceChange() {
|
||||
const provId = this.publishDialog.form.province;
|
||||
await this.loadCities(provId, false);
|
||||
},
|
||||
async onCityChange() {
|
||||
const provId = this.publishDialog.form.province; const cityId = this.publishDialog.form.city;
|
||||
await this.loadAreas(provId, cityId, false);
|
||||
},
|
||||
async loadCities(provId, echo = false) {
|
||||
if (!provId) {
|
||||
this.regionOptions.cities = []; this.regionOptions.areas = [];
|
||||
this.publishDialog.form.city = null; this.publishDialog.form.district = null;
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const res = await getCities(provId);
|
||||
if (res.code === 200) this.regionOptions.cities = res.data || []; else this.$modal.msgError(res.msg || '加载城市失败');
|
||||
} catch (e) { this.$modal.msgError('加载城市失败'); }
|
||||
if (echo && this.publishDialog.form.city) {
|
||||
await this.loadAreas(provId, this.publishDialog.form.city, true);
|
||||
} else {
|
||||
this.regionOptions.areas = []; this.publishDialog.form.district = null;
|
||||
}
|
||||
},
|
||||
async loadAreas(provId, cityId, echo = false) {
|
||||
if (!provId || !cityId) {
|
||||
this.regionOptions.areas = []; this.publishDialog.form.district = null;
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const res = await getAreas(provId, cityId);
|
||||
if (res.code === 200) this.regionOptions.areas = res.data || []; else this.$modal.msgError(res.msg || '加载区县失败');
|
||||
} catch (e) { this.$modal.msgError('加载区县失败'); }
|
||||
if (!echo) {
|
||||
this.publishDialog.form.district = null;
|
||||
}
|
||||
},
|
||||
|
||||
async onItemBizTypeChange() {
|
||||
this.categoryOptions = [];
|
||||
this.publishDialog.form.channelCatId = '';
|
||||
await this.loadCategories();
|
||||
},
|
||||
async onSpBizTypeChange() {
|
||||
this.categoryOptions = [];
|
||||
this.publishDialog.form.channelCatId = '';
|
||||
await this.loadCategories();
|
||||
},
|
||||
async loadCategories() {
|
||||
const itemBizType = this.publishDialog.form.itemBizType;
|
||||
const spBizType = this.publishDialog.form.spBizType;
|
||||
const appid = this.publishDialog.form.appid;
|
||||
if (!itemBizType) return;
|
||||
this.categoryLoading = true;
|
||||
try {
|
||||
const res = await getCategories({ itemBizType, spBizType, appid });
|
||||
if (res.code === 200) this.categoryOptions = res.data || []; else this.$modal.msgError(res.msg || '加载类目失败');
|
||||
} catch (e) { this.$modal.msgError('加载类目失败'); }
|
||||
this.categoryLoading = false;
|
||||
// 若已有选中的类目,或列表首项存在,则尝试自动拉取属性
|
||||
if (this.publishDialog.form.channelCatId) {
|
||||
this.loadProperties();
|
||||
} else if (this.categoryOptions.length) {
|
||||
this.publishDialog.form.channelCatId = this.categoryOptions[0].value;
|
||||
this.loadProperties();
|
||||
}
|
||||
},
|
||||
|
||||
async loadUsernames() {
|
||||
this.userNameLoading = true;
|
||||
try {
|
||||
const res = await getUsernames({ pageNum: 1, pageSize: 200, appid: this.publishDialog.form.appid });
|
||||
if (res.code === 200) this.userNameOptions = res.data || []; else this.$modal.msgError(res.msg || '加载会员名失败');
|
||||
} catch (e) { this.$modal.msgError('加载会员名失败'); }
|
||||
this.userNameLoading = false;
|
||||
if (!this.publishDialog.form.userName && this.userNameOptions.length) {
|
||||
// 如未选择默认填第一个
|
||||
this.publishDialog.form.userName = this.userNameOptions[0].value;
|
||||
}
|
||||
},
|
||||
|
||||
async loadERPAccounts() {
|
||||
this.erpAccountLoading = true;
|
||||
try {
|
||||
const res = await getERPAccounts();
|
||||
if (res.code === 200) this.erpAccountsOptions = res.data || []; else this.$modal.msgError(res.msg || '加载应用失败');
|
||||
} catch (e) { this.$modal.msgError('加载应用失败'); }
|
||||
this.erpAccountLoading = false;
|
||||
if (!this.publishDialog.form.appid && this.erpAccountsOptions.length) {
|
||||
this.publishDialog.form.appid = this.erpAccountsOptions[0].value;
|
||||
}
|
||||
},
|
||||
|
||||
onAppidChange() {
|
||||
// 切换账号后,重新拉取与账号相关的下拉
|
||||
this.publishDialog.form.userName = '';
|
||||
this.loadUsernames();
|
||||
this.loadCategories();
|
||||
this.loadProperties();
|
||||
},
|
||||
|
||||
async loadProperties() {
|
||||
const f = this.publishDialog.form;
|
||||
if (!f.itemBizType || !f.spBizType || !f.channelCatId) {
|
||||
this.pvOptions = []; this.selectedPv = {}; return;
|
||||
}
|
||||
try {
|
||||
const res = await getProperties({ itemBizType: f.itemBizType, spBizType: f.spBizType, channelCatId: f.channelCatId, appid: f.appid });
|
||||
if (res.code === 200) {
|
||||
this.pvOptions = res.data || [];
|
||||
const keep = { ...this.selectedPv };
|
||||
this.selectedPv = {};
|
||||
(this.pvOptions || []).forEach(p => { if (keep[p.propertyId]) this.selectedPv[p.propertyId] = keep[p.propertyId]; });
|
||||
} else {
|
||||
this.$modal.msgError(res.msg || '加载属性失败');
|
||||
}
|
||||
} catch (e) {
|
||||
this.$modal.msgError('加载属性失败');
|
||||
}
|
||||
},
|
||||
|
||||
submitPublish() {
|
||||
this.$refs.publishForm.validate(valid => {
|
||||
if (!valid) return;
|
||||
const f = this.publishDialog.form;
|
||||
const selectedImages = (this.publishDialog.productImages || [])
|
||||
.filter(it => it.selected)
|
||||
.map(it => it.url)
|
||||
.filter(Boolean);
|
||||
const extraImages = String(f.extraImagesText || '')
|
||||
.split(/\n+/)
|
||||
.map(s => s.trim())
|
||||
.filter(Boolean);
|
||||
const images = [...selectedImages, ...extraImages];
|
||||
if (!images.length) {
|
||||
this.$modal.msgError('请至少选择或填写一张图片');
|
||||
return;
|
||||
}
|
||||
let channelPv = undefined;
|
||||
if (f.channelPvJson && f.channelPvJson.trim()) {
|
||||
try { channelPv = JSON.parse(f.channelPvJson); } catch (e) { this.$modal.msgError('属性JSON格式不正确'); return; }
|
||||
}
|
||||
const payload = {
|
||||
appid: f.appid || undefined,
|
||||
title: f.title,
|
||||
content: f.content,
|
||||
images: images,
|
||||
whiteImages: f.whiteImages || undefined,
|
||||
userName: f.userName,
|
||||
province: f.province,
|
||||
city: f.city,
|
||||
district: f.district,
|
||||
serviceSupport: (f.serviceSupport && f.serviceSupport.length) ? f.serviceSupport.join(',') : undefined,
|
||||
price: cents(f.price),
|
||||
originalPrice: f.originalPrice != null ? cents(f.originalPrice) : undefined,
|
||||
expressFee: cents(f.expressFee),
|
||||
stock: f.stock,
|
||||
outerId: f.outerId || undefined,
|
||||
itemBizType: f.itemBizType,
|
||||
spBizType: f.spBizType,
|
||||
channelCatId: f.channelCatId,
|
||||
stuffStatus: f.stuffStatus || undefined,
|
||||
channelPv: channelPv
|
||||
};
|
||||
function cents(yuan) {
|
||||
const n = Number(yuan);
|
||||
if (Number.isNaN(n)) return undefined;
|
||||
return Math.round(n * 100);
|
||||
}
|
||||
this.publishDialog.loading = true;
|
||||
createProductByPromotion(payload).then(res => {
|
||||
this.publishDialog.loading = false;
|
||||
if (res.code === 200) {
|
||||
this.$modal.msgSuccess('发品提交成功');
|
||||
this.publishDialog.visible = false;
|
||||
} else {
|
||||
this.$modal.msgError(res.msg || '发品失败');
|
||||
}
|
||||
}).catch(err => {
|
||||
this.publishDialog.loading = false;
|
||||
console.error('发品失败', err);
|
||||
this.$modal.msgError('发品失败,请稍后重试');
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -278,4 +797,28 @@ export default {
|
||||
.clearfix:after {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.img-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
|
||||
gap: 10px;
|
||||
}
|
||||
.img-item {
|
||||
border: 1px solid #e5e5e5;
|
||||
border-radius: 4px;
|
||||
padding: 6px;
|
||||
text-align: center;
|
||||
}
|
||||
.img-item img {
|
||||
width: 100%;
|
||||
height: 100px;
|
||||
object-fit: cover;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.img-actions {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-top: 6px;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user