728 lines
26 KiB
Vue
728 lines
26 KiB
Vue
<template>
|
||
<div class="app-container">
|
||
<el-card class="box-card">
|
||
<div slot="header" class="clearfix">
|
||
<span>一键转链</span>
|
||
</div>
|
||
|
||
<el-row :gutter="20">
|
||
<el-col :span="12">
|
||
<el-form :model="form" label-width="120px" label-position="top">
|
||
<el-form-item label="输入内容">
|
||
<el-input
|
||
v-model="form.inputContent"
|
||
type="textarea"
|
||
:rows="10"
|
||
placeholder="请输入需要转链的内容,如商品链接、商品名称等"
|
||
style="width: 100%"
|
||
/>
|
||
</el-form-item>
|
||
|
||
<el-form-item>
|
||
<el-button type="primary" @click="handleGenerate" :loading="loading">
|
||
生成转链内容
|
||
</el-button>
|
||
<el-button @click="handleClear">清空</el-button>
|
||
</el-form-item>
|
||
</el-form>
|
||
</el-col>
|
||
<el-col :span="12">
|
||
<el-form label-position="top">
|
||
<el-form-item label="通用文案">
|
||
<el-input
|
||
:value="generalCopy"
|
||
type="textarea"
|
||
:rows="10"
|
||
readonly
|
||
placeholder="暂无通用文案"
|
||
style="width: 100%"
|
||
/>
|
||
</el-form-item>
|
||
<div style="margin-top: 10px;">
|
||
<el-button type="success" @click="handleCopyText(generalCopy)" :disabled="!generalCopy">复制通用文案</el-button>
|
||
</div>
|
||
</el-form>
|
||
</el-col>
|
||
</el-row>
|
||
|
||
<div v-if="result" style="margin-top: 20px;">
|
||
<h4>转链结果:</h4>
|
||
|
||
<!-- 商品列表 -->
|
||
<div v-if="parsedResult && Array.isArray(parsedResult) && parsedResult.length > 0" style="margin-bottom: 20px;">
|
||
<h5>商品列表 ({{ parsedResult.length }}个商品):</h5>
|
||
|
||
<el-tabs v-model="activeProductTab" type="card">
|
||
<el-tab-pane
|
||
v-for="(product, productIndex) in parsedResult"
|
||
:key="productIndex"
|
||
:label="`商品${productIndex + 1}`"
|
||
:name="productIndex"
|
||
>
|
||
<!-- 商品基本信息 -->
|
||
<el-descriptions :column="2" border style="margin-bottom: 20px;">
|
||
<el-descriptions-item label="商品名称">{{ product.skuName || '-' }}</el-descriptions-item>
|
||
<el-descriptions-item label="店铺">{{ product.shopName || '-' }}</el-descriptions-item>
|
||
<el-descriptions-item label="佣金">¥{{ product.commission || '-' }}</el-descriptions-item>
|
||
<el-descriptions-item label="佣金比例">{{ product.commissionShare || '-' }}%</el-descriptions-item>
|
||
<el-descriptions-item label="SPUID">{{ product.spuid || '-' }}</el-descriptions-item>
|
||
<el-descriptions-item label="商品链接">
|
||
<a :href="product.url || '#'" target="_blank" style="color: #409EFF;">{{ product.url || '-' }}</a>
|
||
</el-descriptions-item>
|
||
</el-descriptions>
|
||
|
||
<!-- 文案版本 -->
|
||
<div v-if="product.wenan && Array.isArray(product.wenan) && product.wenan.length > 0" style="margin-bottom: 20px;">
|
||
<h6>文案版本 ({{ product.wenan.length }}个):</h6>
|
||
<el-tabs v-model="activeWenanTab[productIndex]" type="border-card">
|
||
<el-tab-pane
|
||
v-for="(wenan, wenanIndex) in product.wenan"
|
||
:key="wenanIndex"
|
||
:label="wenan.type || `版本${wenanIndex + 1}`"
|
||
:name="wenanIndex"
|
||
>
|
||
<el-input
|
||
:value="wenan.content || ''"
|
||
type="textarea"
|
||
:rows="8"
|
||
readonly
|
||
style="width: 100%"
|
||
/>
|
||
<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>
|
||
</div>
|
||
|
||
<!-- 商品图片 -->
|
||
<div v-if="product.images && Array.isArray(product.images) && product.images.length > 0" style="margin-bottom: 20px;">
|
||
<h6>商品图片 ({{ product.images.length }}张):</h6>
|
||
<div style="display: flex; flex-wrap: wrap; gap: 10px;">
|
||
<div
|
||
v-for="(image, imageIndex) in product.images"
|
||
:key="imageIndex"
|
||
style="text-align: center;"
|
||
>
|
||
<img
|
||
:src="image"
|
||
:alt="`商品${productIndex + 1}图片${imageIndex + 1}`"
|
||
style="width: 120px; height: 120px; object-fit: cover; border: 1px solid #ddd; border-radius: 4px;"
|
||
@click="handlePreviewImage(image)"
|
||
/>
|
||
<div style="margin-top: 5px; font-size: 12px; color: #666;">
|
||
<el-button type="text" size="mini" @click="handleCopyImageUrl(image)">复制链接</el-button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 发品操作 -->
|
||
<div style="margin-top: 10px; display:flex; gap:8px;">
|
||
<el-button type="primary" @click="openPublish(product, productIndex)">发品</el-button>
|
||
<el-button @click="handleAddToFavorites(product)">加入常用</el-button>
|
||
</div>
|
||
</el-tab-pane>
|
||
</el-tabs>
|
||
</div>
|
||
|
||
<!-- 原始数据 -->
|
||
<div style="margin-top: 20px;">
|
||
<h5>原始数据:</h5>
|
||
<el-input
|
||
:value="result"
|
||
type="textarea"
|
||
:rows="6"
|
||
readonly
|
||
style="width: 100%"
|
||
/>
|
||
<div style="margin-top: 10px;">
|
||
<el-button type="success" @click="handleCopy">复制原始数据</el-button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</el-card>
|
||
|
||
<!-- 公共发品对话框组件 -->
|
||
<PublishDialog :visible.sync="publishDialogVisible" :initial-data="publishInitialData" @success="handlePublishSuccess" />
|
||
</div>
|
||
</template>
|
||
|
||
<script>
|
||
import { generatePromotionContent } from "@/api/system/jdorder";
|
||
import { addToFavorites, getBySkuid } from "@/api/system/favoriteProduct";
|
||
import { addToFavoritesAfterPublishFromTransfer } from "@/utils/publishHelper";
|
||
import PublishDialog from '@/components/PublishDialog.vue'
|
||
|
||
export default {
|
||
name: "Jdorder",
|
||
components: { PublishDialog },
|
||
data() {
|
||
return {
|
||
form: {
|
||
inputContent: ""
|
||
},
|
||
loading: false,
|
||
result: "",
|
||
parsedResult: {},
|
||
// 当前选中的商品
|
||
activeProductTab: 0,
|
||
// 每个商品的文案标签页状态
|
||
activeWenanTab: {},
|
||
publishDialogVisible: false,
|
||
publishInitialData: {},
|
||
// 记录正在发品的商品,用于发品成功后自动加入常用
|
||
currentPublishProduct: null,
|
||
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() {},
|
||
computed: {
|
||
// 提取通用文案:优先取第一个商品中类型包含“通用”的文案;否则取第一个文案
|
||
generalCopy() {
|
||
const data = this.parsedResult;
|
||
try {
|
||
if (Array.isArray(data) && data.length) {
|
||
const productIndex = typeof this.activeProductTab === 'number' ? this.activeProductTab : 0;
|
||
const product = data[productIndex] || data[0];
|
||
const wenanList = Array.isArray(product && product.wenan) ? product.wenan : [];
|
||
if (wenanList.length) {
|
||
const found = wenanList.find(w => (w && (w.type || '').includes('通用')));
|
||
const chosen = found || wenanList[0];
|
||
return (chosen && chosen.content) ? chosen.content : '';
|
||
}
|
||
}
|
||
if (data && data.generalCopy) {
|
||
return String(data.generalCopy || '');
|
||
}
|
||
} catch (e) { /* 忽略提取异常 */ }
|
||
return '';
|
||
}
|
||
},
|
||
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: {
|
||
async handleAddToFavorites(product) {
|
||
try {
|
||
const payload = {
|
||
skuid: product.skuid || product.skuId || product.spuid || '',
|
||
productName: product.skuName || product.title || '',
|
||
shopName: product.shopName || '',
|
||
productUrl: product.materialUrl || product.url || '',
|
||
productImage: Array.isArray(product.images) && product.images.length ? product.images[0] : '',
|
||
price: product.price != null ? String(product.price) : (product.lowestCouponPrice != null ? String(product.lowestCouponPrice) : ''),
|
||
commissionInfo: product.commission != null ? String(product.commission) : '',
|
||
remark: '来自一键转链'
|
||
}
|
||
const res = await addToFavorites(payload)
|
||
if (res && (res.code === 200 || res.msg === '操作成功')) {
|
||
this.$modal.msgSuccess('已加入常用');
|
||
} else {
|
||
this.$modal.msgError(res && res.msg ? res.msg : '加入常用失败');
|
||
}
|
||
} catch (e) {
|
||
this.$modal.msgError('加入常用失败');
|
||
}
|
||
},
|
||
handleGenerate() {
|
||
if (!this.form.inputContent.trim()) {
|
||
this.$modal.msgError("请输入需要转链的内容");
|
||
return;
|
||
}
|
||
|
||
this.loading = true;
|
||
generatePromotionContent({
|
||
promotionContent: this.form.inputContent.trim()
|
||
}).then(response => {
|
||
this.loading = false;
|
||
if (response.code === 200) {
|
||
this.result = response.msg || response.data || "转链成功";
|
||
try {
|
||
if (typeof this.result === 'string') {
|
||
this.parsedResult = JSON.parse(this.result);
|
||
} else {
|
||
this.parsedResult = this.result;
|
||
}
|
||
// 初始化每个商品的文案标签页状态
|
||
if (Array.isArray(this.parsedResult)) {
|
||
this.parsedResult.forEach((_, index) => {
|
||
this.$set(this.activeWenanTab, index, 0);
|
||
});
|
||
}
|
||
} catch (e) {
|
||
console.log('数据解析失败,使用原始数据');
|
||
this.parsedResult = {};
|
||
}
|
||
this.$modal.msgSuccess("转链内容生成成功");
|
||
} else {
|
||
this.$modal.msgError(response.msg || "转链失败");
|
||
}
|
||
}).catch(error => {
|
||
this.loading = false;
|
||
console.error('转链失败:', error);
|
||
this.$modal.msgError("转链失败,请稍后重试");
|
||
});
|
||
},
|
||
|
||
handleClear() {
|
||
this.form.inputContent = "";
|
||
this.result = "";
|
||
this.parsedResult = {};
|
||
this.activeProductTab = 0;
|
||
this.activeWenanTab = {};
|
||
},
|
||
|
||
handleCopy() {
|
||
if (this.result) {
|
||
if (navigator.clipboard) {
|
||
navigator.clipboard.writeText(this.result).then(() => {
|
||
this.$modal.msgSuccess("复制成功");
|
||
}).catch(() => {
|
||
this.fallbackCopy();
|
||
});
|
||
} else {
|
||
this.fallbackCopy();
|
||
}
|
||
}
|
||
},
|
||
|
||
fallbackCopy() {
|
||
const textArea = document.createElement("textarea");
|
||
textArea.value = this.result;
|
||
document.body.appendChild(textArea);
|
||
textArea.focus();
|
||
textArea.select();
|
||
try {
|
||
document.execCommand('copy');
|
||
this.$modal.msgSuccess("复制成功");
|
||
} catch (err) {
|
||
this.$modal.msgError("复制失败");
|
||
}
|
||
document.body.removeChild(textArea);
|
||
},
|
||
|
||
handleCopyText(text) {
|
||
if (text) {
|
||
if (navigator.clipboard) {
|
||
navigator.clipboard.writeText(text).then(() => {
|
||
this.$modal.msgSuccess("复制成功");
|
||
}).catch(() => {
|
||
this.fallbackCopyText(text);
|
||
});
|
||
} else {
|
||
this.fallbackCopyText(text);
|
||
}
|
||
}
|
||
},
|
||
|
||
fallbackCopyText(text) {
|
||
const textArea = document.createElement("textarea");
|
||
textArea.value = text;
|
||
document.body.appendChild(textArea);
|
||
textArea.focus();
|
||
textArea.select();
|
||
try {
|
||
document.execCommand('copy');
|
||
this.$modal.msgSuccess("复制成功");
|
||
} catch (err) {
|
||
this.$modal.msgError("复制失败");
|
||
}
|
||
document.body.removeChild(textArea);
|
||
},
|
||
|
||
handleCopyImageUrl(imageUrl) {
|
||
if (imageUrl) {
|
||
if (navigator.clipboard) {
|
||
navigator.clipboard.writeText(imageUrl).then(() => {
|
||
this.$modal.msgSuccess("图片链接复制成功");
|
||
}).catch(() => {
|
||
this.fallbackCopyText(imageUrl);
|
||
});
|
||
} else {
|
||
this.fallbackCopyText(imageUrl);
|
||
}
|
||
}
|
||
},
|
||
|
||
handlePreviewImage(imageUrl) {
|
||
window.open(imageUrl, '_blank');
|
||
},
|
||
|
||
openPublish(product, productIndex) {
|
||
const wenanIndex = this.activeWenanTab[productIndex] || 0;
|
||
const wenanOptions = Array.isArray(product.wenan) ? product.wenan.map((w, i) => ({ label: w.type || `版本${i+1}`, content: w.content || '' })) : [];
|
||
// 记录当前发品的商品
|
||
this.currentPublishProduct = product;
|
||
this.publishInitialData = {
|
||
title: product.skuName || '',
|
||
content: (product && product.wenan && product.wenan[wenanIndex] ? (product.wenan[wenanIndex].content || '') : ''),
|
||
images: Array.isArray(product.images) ? product.images : [],
|
||
originalPrice: this.guessYuanPrice(product),
|
||
wenanOptions
|
||
};
|
||
this.publishDialogVisible = true;
|
||
},
|
||
async handlePublishSuccess(res) {
|
||
try {
|
||
const p = this.currentPublishProduct || {};
|
||
await addToFavoritesAfterPublishFromTransfer(p, res);
|
||
this.$store && this.$store.dispatch && this.$store.dispatch('app/triggerFavoriteProductRefresh');
|
||
} catch (e) { }
|
||
},
|
||
|
||
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) {
|
||
// 成功反馈:包含生成的outerId
|
||
try {
|
||
const outerId = res.data && (res.data.outerId || (res.data.data && res.data.data.outerId))
|
||
if (outerId) {
|
||
this.$modal.msgSuccess(`发品成功,商家编码:${outerId}`)
|
||
} else {
|
||
this.$modal.msgSuccess('发品提交成功')
|
||
}
|
||
} catch (e) {
|
||
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('发品失败,请稍后重试');
|
||
});
|
||
});
|
||
}
|
||
}
|
||
};
|
||
</script>
|
||
|
||
<style scoped>
|
||
.box-card {
|
||
margin: 20px;
|
||
}
|
||
|
||
.clearfix:before,
|
||
.clearfix:after {
|
||
display: table;
|
||
content: "";
|
||
}
|
||
.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>
|