Files
ruoyi-vue/src/views/system/favoriteProduct/index.vue
2025-08-25 01:46:41 +08:00

632 lines
22 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="商品名称" prop="productName">
<el-input
v-model="queryParams.productName"
placeholder="请输入商品名称"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="店铺名称" prop="shopName">
<el-input
v-model="queryParams.shopName"
placeholder="请输入店铺名称"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="SKUID" prop="skuid">
<el-input
v-model="queryParams.skuid"
placeholder="请输入SKUID"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="是否置顶" prop="isTop">
<el-select v-model="queryParams.isTop" placeholder="请选择" clearable>
<el-option label="是" :value="1" />
<el-option label="否" :value="0" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button
type="primary"
plain
icon="el-icon-plus"
size="mini"
@click="handleAdd"
v-hasPermi="['jarvis:favoriteProduct:add']"
>新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="success"
plain
icon="el-icon-edit"
size="mini"
:disabled="single"
@click="handleUpdate"
v-hasPermi="['jarvis:favoriteProduct:edit']"
>修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
plain
icon="el-icon-delete"
size="mini"
:disabled="multiple"
@click="handleDelete"
v-hasPermi="['jarvis:favoriteProduct:remove']"
>删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="warning"
plain
icon="el-icon-top"
size="mini"
:disabled="multiple"
@click="handleBatchTop"
v-hasPermi="['jarvis:favoriteProduct:edit']"
>批量置顶</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="info"
plain
icon="el-icon-download"
size="mini"
@click="handleExport"
v-hasPermi="['jarvis:favoriteProduct:export']"
>导出</el-button>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-table v-loading="loading" :data="favoriteProductList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="商品图片" align="center" prop="productImage" width="100">
<template slot-scope="scope">
<el-image
v-if="scope.row.productImage"
:src="scope.row.productImage"
:preview-src-list="[scope.row.productImage]"
style="width: 60px; height: 60px; border-radius: 4px;"
fit="cover"
/>
<span v-else>-</span>
</template>
</el-table-column>
<el-table-column label="商品名称" align="left" prop="productName" min-width="200" :show-overflow-tooltip="true">
<template slot-scope="scope">
<div>
<div style="font-weight: bold; margin-bottom: 5px;">
<el-tag v-if="scope.row.isTop === 1" type="danger" size="mini">置顶</el-tag>
{{ scope.row.productName }}
</div>
<div style="color: #666; font-size: 12px;">
SKUID: {{ scope.row.skuid }}
</div>
</div>
</template>
</el-table-column>
<el-table-column label="店铺信息" align="left" prop="shopName" min-width="150">
<template slot-scope="scope">
<div>
<div>{{ scope.row.shopName }}</div>
<div style="color: #666; font-size: 12px;">ID: {{ scope.row.shopId }}</div>
</div>
</template>
</el-table-column>
<el-table-column label="价格信息" align="center" prop="price" width="120">
<template slot-scope="scope">
<div>
<div style="color: #f56c6c; font-weight: bold;">¥{{ scope.row.price || '-' }}</div>
<div v-if="scope.row.commissionInfo" style="color: #67c23a; font-size: 12px;">
佣金: {{ scope.row.commissionInfo }}
</div>
</div>
</template>
</el-table-column>
<el-table-column label="ERP商品" align="center" prop="erpProductIds" width="120">
<template slot-scope="scope">
<el-button
v-if="scope.row.erpProductIds"
type="text"
size="mini"
@click="showErpProducts(scope.row)"
>
查看({{ JSON.parse(scope.row.erpProductIds || '[]').length }})
</el-button>
<span v-else>-</span>
</template>
</el-table-column>
<el-table-column label="使用统计" align="center" width="120">
<template slot-scope="scope">
<div>
<div>使用: {{ scope.row.useCount || 0 }}</div>
<div style="color: #666; font-size: 12px;">
{{ scope.row.lastUsedTime || '未使用' }}
</div>
</div>
</template>
</el-table-column>
<el-table-column label="创建信息" align="center" width="150">
<template slot-scope="scope">
<div>
<div>{{ scope.row.createUserName }}</div>
<div style="color: #666; font-size: 12px;">
{{ parseTime(scope.row.createTime) }}
</div>
</div>
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="200">
<template slot-scope="scope">
<el-button
size="mini"
type="text"
icon="el-icon-view"
@click="handleView(scope.row)"
>查看</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-edit"
@click="handleUpdate(scope.row)"
v-hasPermi="['jarvis:favoriteProduct:edit']"
>修改</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-top"
@click="handleTop(scope.row)"
v-hasPermi="['jarvis:favoriteProduct:edit']"
>
{{ scope.row.isTop === 1 ? '取消置顶' : '置顶' }}
</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-shopping-cart-2"
@click="handleQuickPublish(scope.row)"
>快速发品</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-delete"
@click="handleDelete(scope.row)"
v-hasPermi="['jarvis:favoriteProduct:remove']"
>删除</el-button>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total>0"
:total="total"
:page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize"
@pagination="getList"
/>
<!-- 添加或修改常用商品对话框 -->
<el-dialog :title="title" :visible.sync="open" width="800px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="120px">
<el-row>
<el-col :span="12">
<el-form-item label="SKUID" prop="skuid">
<el-input v-model="form.skuid" placeholder="请输入SKUID" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="商品名称" prop="productName">
<el-input v-model="form.productName" placeholder="请输入商品名称" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="店铺名称" prop="shopName">
<el-input v-model="form.shopName" placeholder="请输入店铺名称" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="店铺ID" prop="shopId">
<el-input v-model="form.shopId" placeholder="请输入店铺ID" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="商品链接" prop="productUrl">
<el-input v-model="form.productUrl" placeholder="请输入商品链接" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="商品图片" prop="productImage">
<el-input v-model="form.productImage" placeholder="请输入商品图片URL" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="商品价格" prop="price">
<el-input v-model="form.price" placeholder="请输入商品价格" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="佣金信息" prop="commissionInfo">
<el-input v-model="form.commissionInfo" placeholder="请输入佣金信息" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="商品分类" prop="category">
<el-input v-model="form.category" placeholder="请输入商品分类" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="商品品牌" prop="brand">
<el-input v-model="form.brand" placeholder="请输入商品品牌" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="是否置顶" prop="isTop">
<el-radio-group v-model="form.isTop">
<el-radio :label="1"></el-radio>
<el-radio :label="0"></el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="排序权重" prop="sortWeight">
<el-input-number v-model="form.sortWeight" :min="0" :max="999" />
</el-form-item>
</el-col>
</el-row>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" type="textarea" placeholder="请输入备注" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</el-dialog>
<!-- ERP商品详情对话框 -->
<el-dialog title="ERP商品详情" :visible.sync="erpDialogVisible" width="800px" append-to-body>
<el-table :data="erpProducts" border style="width: 100%">
<el-table-column label="ERP应用ID" prop="appid" width="120" />
<el-table-column label="ERP商品ID" prop="erpProductId" width="120" />
<el-table-column label="商品标题" prop="erpProductTitle" min-width="200" :show-overflow-tooltip="true" />
<el-table-column label="商品状态" prop="erpProductStatus" width="100">
<template slot-scope="scope">
<el-tag :type="scope.row.erpProductStatus === 'active' ? 'success' : 'info'">
{{ scope.row.erpProductStatus === 'active' ? '正常' : '其他' }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="商品链接" prop="erpProductUrl" min-width="200">
<template slot-scope="scope">
<el-link :href="scope.row.erpProductUrl" target="_blank" type="primary">
查看商品
</el-link>
</template>
</el-table-column>
<el-table-column label="备注" prop="remark" width="120" />
</el-table>
<div slot="footer" class="dialog-footer">
<el-button @click="erpDialogVisible = false"> </el-button>
</div>
</el-dialog>
<!-- 通用发品对话框从常用商品直接进入不显示ERP应用选择 -->
<PublishDialog :visible.sync="publishDialogVisible" :initial-data="publishInitialData" :hideAppid="true" />
</div>
</template>
<script>
import { listFavoriteProduct, getFavoriteProduct, delFavoriteProduct, addFavoriteProduct, updateFavoriteProduct, updateTopStatus } from "@/api/system/favoriteProduct";
import { generatePromotionContent } from "@/api/system/jdorder";
import { mapGetters, mapActions } from 'vuex'
import PublishDialog from '@/components/PublishDialog.vue'
// 自动加入常用逻辑由 PublishDialog 内部触发(线报、转链页面),本页主要用于打开发品弹窗
export default {
name: "FavoriteProduct",
components: { PublishDialog },
computed: {
...mapGetters(['favoriteProductRefreshKey'])
},
data() {
return {
// 遮罩层
loading: true,
// 选中数组
ids: [],
// 非单个禁用
single: true,
// 非多个禁用
multiple: true,
// 显示搜索条件
showSearch: true,
// 总条数
total: 0,
// 常用商品表格数据
favoriteProductList: [],
// 弹出层标题
title: "",
// 是否显示弹出层
open: false,
// 查询参数
queryParams: {
pageNum: 1,
pageSize: 10,
productName: null,
shopName: null,
skuid: null,
isTop: null
},
// 表单参数
form: {},
// 表单校验
rules: {
skuid: [
{ required: true, message: "SKUID不能为空", trigger: "blur" }
],
productName: [
{ required: true, message: "商品名称不能为空", trigger: "blur" }
],
shopName: [
{ required: true, message: "店铺名称不能为空", trigger: "blur" }
]
},
// ERP商品对话框
erpDialogVisible: false,
erpProducts: [],
// 通用发品弹窗
publishDialogVisible: false,
publishInitialData: {}
};
},
created() {
this.getList();
},
watch: {
favoriteProductRefreshKey() {
// 全局刷新标记变更时,自动刷新列表
this.getList();
}
},
methods: {
/** 查询常用商品列表 */
getList() {
this.loading = true;
listFavoriteProduct(this.queryParams).then(response => {
this.favoriteProductList = response.rows;
this.total = response.total;
this.loading = false;
});
},
// 取消按钮
cancel() {
this.open = false;
this.reset();
},
// 表单重置
reset() {
this.form = {
id: null,
skuid: null,
productName: null,
shopName: null,
shopId: null,
productUrl: null,
productImage: null,
price: null,
commissionInfo: null,
isTop: 0,
sortWeight: 0,
remark: null,
category: null,
brand: null
};
this.resetForm("form");
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1;
this.getList();
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm("queryForm");
this.handleQuery();
},
// 多选框选中数据
handleSelectionChange(selection) {
this.ids = selection.map(item => item.id)
this.single = selection.length!==1
this.multiple = !selection.length
},
/** 新增按钮操作 */
handleAdd() {
this.reset();
this.open = true;
this.title = "添加常用商品";
},
/** 修改按钮操作 */
handleUpdate(row) {
this.reset();
const id = row.id || this.ids
getFavoriteProduct(id).then(response => {
this.form = response.data;
this.open = true;
this.title = "修改常用商品";
});
},
/** 查看按钮操作 */
handleView(row) {
this.reset();
const id = row.id || this.ids
getFavoriteProduct(id).then(response => {
this.form = response.data;
this.open = true;
this.title = "查看常用商品";
// 设置为只读
this.$nextTick(() => {
Object.keys(this.form).forEach(key => {
const input = this.$refs.form.$el.querySelector(`[name="${key}"]`);
if (input) {
input.disabled = true;
}
});
});
});
},
/** 提交按钮 */
submitForm() {
this.$refs["form"].validate(valid => {
if (valid) {
if (this.form.id != null) {
updateFavoriteProduct(this.form).then(response => {
this.$modal.msgSuccess("修改成功");
this.open = false;
this.getList();
});
} else {
addFavoriteProduct(this.form).then(response => {
this.$modal.msgSuccess("新增成功");
this.open = false;
this.getList();
});
}
}
});
},
/** 删除按钮操作 */
handleDelete(row) {
const ids = row.id || this.ids;
this.$modal.confirm('是否确认删除常用商品编号为"' + ids + '"的数据项?').then(function() {
return delFavoriteProduct(ids);
}).then(() => {
this.getList();
this.$modal.msgSuccess("删除成功");
}).catch(() => {});
},
/** 置顶按钮操作 */
handleTop(row) {
const isTop = row.isTop === 1 ? 0 : 1;
const action = isTop === 1 ? '置顶' : '取消置顶';
this.$modal.confirm('是否确认' + action + '商品"' + row.productName + '"').then(function() {
return updateTopStatus(row.id, isTop);
}).then(() => {
this.getList();
this.$modal.msgSuccess(action + "成功");
}).catch(() => {});
},
/** 批量置顶操作 */
handleBatchTop() {
this.$modal.confirm('是否确认批量置顶选中的商品?').then(function() {
// 这里需要调用批量置顶接口
return Promise.resolve();
}).then(() => {
this.getList();
this.$modal.msgSuccess("批量置顶成功");
}).catch(() => {});
},
/** 导出按钮操作 */
handleExport() {
this.download('jarvis/favoriteProduct/export', {
...this.queryParams
}, `favoriteProduct_${new Date().getTime()}.xlsx`)
},
/** 显示ERP商品详情 */
showErpProducts(row) {
try {
this.erpProducts = JSON.parse(row.erpProductIds || '[]');
this.erpDialogVisible = true;
} catch (e) {
this.$modal.msgError("ERP商品数据格式错误");
}
},
/** 快速发品 */
handleQuickPublish(row) {
const id = row.id || this.ids;
getFavoriteProduct(id).then(async res => {
const p = res && res.data ? res.data : (row || {});
try {
// 与转链保持一致:优先使用保存的商品链接,避免用名称/ID 产生歧义
if (!p.productUrl) {
this.$modal.msgWarning('该常用商品缺少商品链接,无法生成完整发品信息');
}
let detail = null;
if (p.productUrl) {
const r = await generatePromotionContent({ promotionContent: p.productUrl });
const resultStr = (r && (r.msg || r.data)) || '';
try { const arr = typeof resultStr === 'string' ? JSON.parse(resultStr) : resultStr; if (Array.isArray(arr) && arr.length) detail = arr[0]; } catch(e) {}
}
const images = Array.isArray(detail && detail.images) && detail.images.length ? detail.images : (p.productImage ? [p.productImage] : []);
const wenanArr = Array.isArray(detail && detail.wenan) ? detail.wenan : [];
const wenanOptions = wenanArr.map((w, i) => ({ label: w.type || `版本${i+1}` , content: w.content || '' }));
this.publishInitialData = {
title: (detail && (detail.skuName || detail.title)) || p.productName || '',
content: (wenanOptions[0] && wenanOptions[0].content) || '',
images: images,
originalPrice: detail && detail.price ? Number(detail.price) : (p.price ? Number(p.price) : undefined),
wenanOptions: wenanOptions,
userName: p.userName || '',
province: p.province || null,
city: p.city || null,
district: p.district || null
};
this.publishDialogVisible = true;
} catch (e) {
const imagesFallback = p.productImage ? [p.productImage] : [];
this.publishInitialData = { title: p.productName || '', images: imagesFallback, content: '' };
this.publishDialogVisible = true;
}
}).catch(() => {
const images = row && row.productImage ? [row.productImage] : [];
this.publishInitialData = { title: row.productName || '', images, content: '' };
this.publishDialogVisible = true;
});
},
}
};
</script>
<style scoped>
.mb8 {
margin-bottom: 8px;
}
.el-table .el-table__row:hover {
background-color: #f5f7fa;
}
.el-tag {
margin-right: 5px;
}
</style>