|
|
@@ -98,10 +98,12 @@
|
|
|
</template>
|
|
|
|
|
|
<script setup name="Fresh" lang="ts">
|
|
|
-import { ref, reactive, onMounted } from 'vue';
|
|
|
-import { ElMessage } from 'element-plus';
|
|
|
+import { ref, reactive, computed, onMounted, nextTick } from 'vue';
|
|
|
+import { ElMessage, ElMessageBox } from 'element-plus';
|
|
|
import { Picture, CircleClose } from '@element-plus/icons-vue';
|
|
|
import { getDecorationSectionByType, addDecorationSection, updateDecorationSection } from '@/api/decoration/section';
|
|
|
+import { listProduct } from '@/api/product/base';
|
|
|
+import { listRecommend, listRecommendLink, addRecommendLink, delRecommendLink } from '@/api/product/recommend';
|
|
|
|
|
|
// 标题配置
|
|
|
const headerConfig = ref({
|
|
|
@@ -176,24 +178,86 @@ const handleLinkClick = () => {
|
|
|
}
|
|
|
};
|
|
|
|
|
|
-// 商品列表(模拟数据,等同事接口)- 在这里修改图片路径
|
|
|
-const productList = ref([
|
|
|
- { id: 1, name: '联想笔记本电脑', description: '高性能商务本', price: '4999.00', imageUrl: '/img/联想.jpg' },
|
|
|
- { id: 2, name: '惠普打印机', description: '高效办公打印', price: '1299.00', imageUrl: '/img/惠普.jpg' },
|
|
|
- { id: 3, name: '奔图激光打印机', description: '国产高品质', price: '899.00', imageUrl: '/img/奔图.jpg' },
|
|
|
- { id: 4, name: 'MAXHUB会议平板', description: '智能会议解决方案', price: '12999.00', imageUrl: '/img/MAXHUB.jpg' },
|
|
|
- { id: 5, name: '飞利浦显示器', description: '护眼高清屏', price: '1599.00', imageUrl: '/img/PHILIPS.jpg' }
|
|
|
-]);
|
|
|
+// 推荐位编号
|
|
|
+const recommendNo = 'decoration_fresh';
|
|
|
+const recommendId = ref<number | null>(null);
|
|
|
|
|
|
-// 商品操作
|
|
|
-const handleRemoveProduct = (id: number) => {
|
|
|
- const index = productList.value.findIndex(item => item.id === id);
|
|
|
- if (index > -1) {
|
|
|
- productList.value.splice(index, 1);
|
|
|
- ElMessage.success('已移除');
|
|
|
+// 商品列表
|
|
|
+const productList = ref<any[]>([]);
|
|
|
+
|
|
|
+// 获取推荐位ID
|
|
|
+const loadRecommendId = async () => {
|
|
|
+ try {
|
|
|
+ const res: any = await listRecommend({ recommendNo, pageSize: 1 });
|
|
|
+ if (res.rows && res.rows.length > 0) {
|
|
|
+ recommendId.value = res.rows[0].id;
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error('获取推荐位失败', error);
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+// 加载商品列表
|
|
|
+const loadProductList = async () => {
|
|
|
+ try {
|
|
|
+ if (!recommendId.value) {
|
|
|
+ await loadRecommendId();
|
|
|
+ }
|
|
|
+ if (!recommendId.value) {
|
|
|
+ productList.value = [];
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // 获取推荐关联
|
|
|
+ const linkRes: any = await listRecommendLink({ recommendId: recommendId.value, pageSize: 100 });
|
|
|
+ const links = linkRes.rows || [];
|
|
|
+ if (links.length === 0) {
|
|
|
+ productList.value = [];
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // 获取商品详情
|
|
|
+ const productIds = links.map((link: any) => link.productId);
|
|
|
+ const productRes: any = await listProduct({ ids: productIds.join(','), pageSize: 100 });
|
|
|
+ const productMap = new Map((productRes.rows || []).map((p: any) => [p.id, p]));
|
|
|
+ // 组装数据
|
|
|
+ productList.value = links.map((link: any) => {
|
|
|
+ const product: any = productMap.get(link.productId) || {};
|
|
|
+ return {
|
|
|
+ id: product.id || link.productId,
|
|
|
+ linkId: link.id,
|
|
|
+ name: product.itemName || `商品${link.productId}`,
|
|
|
+ description: product.remark || '',
|
|
|
+ price: product.minSellingPrice || product.memberPrice || '0.00',
|
|
|
+ imageUrl: product.productImageUrl || product.productImage
|
|
|
+ };
|
|
|
+ });
|
|
|
+ } catch (error) {
|
|
|
+ console.error('加载商品列表失败', error);
|
|
|
+ productList.value = [];
|
|
|
}
|
|
|
};
|
|
|
|
|
|
+// 移除商品
|
|
|
+const handleRemoveProduct = (id: number) => {
|
|
|
+ const product = productList.value.find((item) => item.id === id);
|
|
|
+ ElMessageBox.confirm('是否确认移除该商品?', '提示', {
|
|
|
+ confirmButtonText: '确定',
|
|
|
+ cancelButtonText: '取消',
|
|
|
+ type: 'warning'
|
|
|
+ })
|
|
|
+ .then(async () => {
|
|
|
+ try {
|
|
|
+ if (product?.linkId) {
|
|
|
+ await delRecommendLink(product.linkId);
|
|
|
+ }
|
|
|
+ await loadProductList();
|
|
|
+ ElMessage.success('已移除');
|
|
|
+ } catch (error) {
|
|
|
+ ElMessage.error('移除失败');
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .catch(() => {});
|
|
|
+};
|
|
|
+
|
|
|
// 排序对话框
|
|
|
const sortDialog = reactive({ visible: false, productId: 0, sortValue: 0 });
|
|
|
const handleSort = (id: number) => {
|
|
|
@@ -206,8 +270,94 @@ const saveSortConfig = () => {
|
|
|
ElMessage.success('排序已保存');
|
|
|
};
|
|
|
|
|
|
+// 选择商品对话框
|
|
|
+const selectDialog = reactive({
|
|
|
+ visible: false,
|
|
|
+ keyword: '',
|
|
|
+ pageNum: 1,
|
|
|
+ pageSize: 10,
|
|
|
+ total: 0
|
|
|
+});
|
|
|
+const availableProducts = ref<any[]>([]);
|
|
|
+const selectedProductIds = ref<number[]>([]);
|
|
|
+const productTableRef = ref();
|
|
|
+
|
|
|
+// 加载可选商品
|
|
|
+const loadAvailableProducts = async () => {
|
|
|
+ try {
|
|
|
+ const params: any = { pageNum: selectDialog.pageNum, pageSize: selectDialog.pageSize };
|
|
|
+ if (selectDialog.keyword) params.itemName = selectDialog.keyword;
|
|
|
+ const res: any = await listProduct(params);
|
|
|
+ availableProducts.value = (res.rows || []).map((item: any) => ({
|
|
|
+ id: item.id,
|
|
|
+ name: item.itemName,
|
|
|
+ imageUrl: item.productImageUrl || item.productImage,
|
|
|
+ price: item.minSellingPrice || item.memberPrice || '0.00'
|
|
|
+ }));
|
|
|
+ selectDialog.total = res.total || 0;
|
|
|
+ } catch (error) {
|
|
|
+ console.error('加载商品失败', error);
|
|
|
+ availableProducts.value = [];
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+// 过滤已选商品
|
|
|
+const filteredAvailableProducts = computed(() => {
|
|
|
+ const selectedIds = productList.value.map((p) => String(p.id));
|
|
|
+ return availableProducts.value.filter((item) => !selectedIds.includes(String(item.id)));
|
|
|
+});
|
|
|
+
|
|
|
+// 新增商品
|
|
|
+const handleAddProduct = () => {
|
|
|
+ selectDialog.keyword = '';
|
|
|
+ selectDialog.pageNum = 1;
|
|
|
+ selectDialog.visible = true;
|
|
|
+ selectedProductIds.value = [];
|
|
|
+ loadAvailableProducts();
|
|
|
+ nextTick(() => { productTableRef.value?.clearSelection(); });
|
|
|
+};
|
|
|
+
|
|
|
+// 选择变化
|
|
|
+const handleSelectionChange = (selection: any[]) => {
|
|
|
+ selectedProductIds.value = selection.map((item) => item.id);
|
|
|
+};
|
|
|
+
|
|
|
+// 确认选择
|
|
|
+const handleConfirmSelect = async () => {
|
|
|
+ if (selectedProductIds.value.length === 0) {
|
|
|
+ ElMessage.warning('请至少选择一个商品');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ if (!recommendId.value) {
|
|
|
+ await loadRecommendId();
|
|
|
+ }
|
|
|
+ if (!recommendId.value) {
|
|
|
+ ElMessage.error('推荐位不存在,请先创建');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ let addedCount = 0;
|
|
|
+ for (const productId of selectedProductIds.value) {
|
|
|
+ if (!productList.value.find((p) => String(p.id) === String(productId))) {
|
|
|
+ await addRecommendLink({ recommendId: recommendId.value, productId });
|
|
|
+ addedCount++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (addedCount > 0) {
|
|
|
+ ElMessage.success(`成功添加 ${addedCount} 个商品`);
|
|
|
+ } else {
|
|
|
+ ElMessage.warning('所选商品均已存在');
|
|
|
+ }
|
|
|
+ selectDialog.visible = false;
|
|
|
+ await loadProductList();
|
|
|
+ } catch (error) {
|
|
|
+ ElMessage.error('添加失败');
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
onMounted(() => {
|
|
|
loadHeaderConfig();
|
|
|
+ loadProductList();
|
|
|
});
|
|
|
</script>
|
|
|
|
|
|
@@ -223,6 +373,13 @@ onMounted(() => {
|
|
|
margin: 0 auto;
|
|
|
}
|
|
|
|
|
|
+.action-card {
|
|
|
+ background: #fff;
|
|
|
+ border-radius: 4px;
|
|
|
+ padding: 15px 20px;
|
|
|
+ margin-bottom: 12px;
|
|
|
+}
|
|
|
+
|
|
|
.section-header-card {
|
|
|
display: flex;
|
|
|
justify-content: space-between;
|
|
|
@@ -341,4 +498,25 @@ onMounted(() => {
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+.search-bar {
|
|
|
+ display: flex;
|
|
|
+ gap: 10px;
|
|
|
+}
|
|
|
+
|
|
|
+.image-placeholder-small {
|
|
|
+ width: 60px;
|
|
|
+ height: 60px;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ background: #f5f5f5;
|
|
|
+ color: #ccc;
|
|
|
+ font-size: 20px;
|
|
|
+}
|
|
|
+
|
|
|
+.price-text {
|
|
|
+ color: #f56c6c;
|
|
|
+ font-weight: 600;
|
|
|
+}
|
|
|
</style>
|