weixin_52219567 1 mēnesi atpakaļ
vecāks
revīzija
f5637c7804

+ 1 - 1
src/components/LinkSelector/index.vue

@@ -565,7 +565,7 @@ const handleQuery2 = () => {
 const getTableData2 = async () => {
   loading2.value = true;
   try {
-    const res = await listBase(queryParams2);
+    const res = await listBase({ productStatus: 1, ...queryParams2 });
     tableData2.value = res.rows || [];
     total2.value = res.total || 0;
   } finally {

+ 4 - 1
src/components/goodsDialog/index.vue

@@ -152,7 +152,10 @@ const getList = async () => {
     } else {
       delete queryParams.customerId;
     }
-    const res = props.clientId && props.clientId != 'undefined' ? await getCustomerProductPage(queryParams) : await listBase(queryParams);
+    const res =
+      props.clientId && props.clientId != 'undefined'
+        ? await getCustomerProductPage(queryParams)
+        : await listBase({ productStatus: 1, ...queryParams });
     tableData.value = res.rows || [];
     let result = [];
     if (props.navIndex || props.navIndex == 0) {

+ 266 - 0
src/components/goodsMini/index.vue

@@ -0,0 +1,266 @@
+<template>
+  <div>
+    <el-dialog v-model="showDialog" title="选择商品" width="1400">
+      <div class="dialog-bos">
+        <div class="flex">
+          <el-tree-select
+            v-model="goodsClassify"
+            :data="categoryOptions"
+            :props="treeProps"
+            value-key="id"
+            placeholder="请选择商品分类"
+            clearable
+            check-strictly
+            @change="goodsClassifyChange"
+            style="width: 300px; margin-bottom: 10px"
+          />
+          <el-input class="ml-[20px]" v-model="queryParams.itemName" placeholder="请输入商品名称" clearable style="width: 300px; margin-bottom: 10px">
+            <template #append>
+              <el-button :icon="Search" @click="handleQuery" />
+            </template>
+          </el-input>
+        </div>
+
+        <div class="flex">
+          <div class="tree-bos">
+            <!-- <el-tree :data="categoryOptions" :props="defaultProps" @node-click="handleNodeClick" :highlight-current="true" /> -->
+          </div>
+          <el-table height="600" ref="multipleTableRef" v-loading="loading" :data="tableData" border @selection-change="handleSelectionChange">
+            <el-table-column type="selection" width="55" />
+            <el-table-column label="商品图片" align="center" prop="productImage" width="100">
+              <template #default="scope">
+                <image-preview :src="scope.row.productImage" :width="60" :height="60" />
+              </template>
+            </el-table-column>
+            <el-table-column label="商品信息" align="center" minWidth="250" show-overflow-tooltip>
+              <template #default="scope">
+                <div class="text-left">
+                  <div>{{ scope.row.itemName }}</div>
+                  <div class="text-gray-500" style="font-size: 12px">品牌: {{ scope.row.brandName || '-' }}</div>
+                </div>
+              </template>
+            </el-table-column>
+            <el-table-column label="SKU价格" align="center" width="180">
+              <template #default="scope">
+                <div class="text-left" style="font-size: 12px">
+                  <div>
+                    <span class="text-gray-500">市场价:</span>
+                    <span class="text-red-500">¥{{ scope.row.marketPrice || '0.00' }}</span>
+                  </div>
+                  <div>
+                    <span class="text-gray-500">会员价:</span>
+                    <span class="text-red-500">¥{{ scope.row.memberPrice || '0.00' }}</span>
+                  </div>
+                  <div>
+                    <span class="text-gray-500">最低价:</span>
+                    <span class="text-red-500">¥{{ scope.row.minSellingPrice || '0.00' }}</span>
+                  </div>
+                </div>
+              </template>
+            </el-table-column>
+            <el-table-column label="成本情况" align="center" width="150">
+              <template #default="scope">
+                <div class="text-left" style="font-size: 12px">
+                  <div>
+                    <span class="text-gray-500">采购价:</span>
+                    <span>¥{{ scope.row.purchasingPrice || '0.00' }}</span>
+                  </div>
+                  <div>
+                    <span class="text-gray-500">暂估毛利率:</span>
+                    <span>{{ scope.row.tempGrossMargin || '0.0000' }}%</span>
+                  </div>
+                </div>
+              </template>
+            </el-table-column>
+          </el-table>
+        </div>
+        <pagination v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" :total="total" @pagination="getList">
+          <template #slotDiv>
+            <div class="selected">已选择 {{ multipleSelection.length }} 个</div>
+          </template>
+        </pagination>
+      </div>
+
+      <template #footer>
+        <span class="dialog-footer">
+          <el-button @click="showDialog = false">取消</el-button>
+          <el-button type="primary" @click="onConfirm">确认</el-button>
+        </span>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { Search } from '@element-plus/icons-vue';
+import { listBase } from '@/api/pmsProduct/base';
+import useDiyStore from '@/store/modules/diy';
+import type { TableInstance } from 'element-plus';
+import { getCustomerProductPage } from '@/api/diy/index';
+import { el } from 'element-plus/es/locale/index.mjs';
+const goodsClassify = ref<any>('');
+const diyStore: any = useDiyStore();
+const showDialog = ref(false);
+const loading = ref(false);
+const tableData = ref<any[]>([]);
+const resultList = ref<any>([]); //单页之前被选中的数据
+const multipleSelection: any = ref([]); // 选中数据
+const multipleTableRef = ref<TableInstance>();
+const total = ref(0);
+const queryParams = reactive({
+  pageNum: 1,
+  pageSize: 10,
+  itemName: '',
+  topCategoryId: '',
+  mediumCategoryId: '',
+  bottomCategoryId: '',
+  customerId: ''
+});
+const treeProps = {
+  value: 'id',
+  label: 'label',
+  children: 'children'
+};
+const props = defineProps<{
+  categoryOptions?: any;
+  navIndex?: any;
+  clientId?: any;
+  type?: any;
+}>();
+const onOpen = () => {
+  console.log('打开弹窗');
+  showDialog.value = true;
+  getList();
+};
+
+// 监听表格单行选中
+const handleSelectionChange = (val: []) => {
+  multipleSelection.value = val;
+};
+
+/** 搜索 */
+const handleQuery = () => {
+  queryParams.pageNum = 1;
+  getList();
+};
+
+/** 获取列表 */
+const getList = async () => {
+  loading.value = true;
+  try {
+    if (props.clientId && props.clientId != 'undefined') {
+      queryParams.customerId = props.clientId;
+    } else {
+      delete queryParams.customerId;
+    }
+    const res =
+      props.clientId && props.clientId != 'undefined'
+        ? await getCustomerProductPage(queryParams)
+        : await listBase({ productStatus: 1, ...queryParams });
+    tableData.value = res.rows || [];
+    let result = [];
+    if (props.navIndex || props.navIndex == 0) {
+      if (props.type == 'editManyGoodsList') {
+        result = tableData.value.filter((item: any) => diyStore.editComponent.list[props.navIndex].goods_ids.includes(item.id));
+      }
+    } else {
+      result = tableData.value.filter((item: any) => diyStore.editComponent.goodsIds.includes(item.id));
+    }
+    resultList.value = result;
+    nextTick(() => {
+      result.forEach((item: any) => {
+        multipleTableRef.value?.toggleRowSelection(item, true);
+      });
+    });
+    total.value = res.total || 0;
+  } finally {
+    loading.value = false;
+  }
+};
+
+//确定
+const onConfirm = () => {
+  if (props.navIndex || props.navIndex == 0) {
+    if (props.type == 'editManyGoodsList') {
+      const newIds = calculateNewIds(diyStore.editComponent.list[props.navIndex].goods_ids, tableData.value, multipleSelection.value);
+      // console.log(newIds,'?????????????')
+      // return
+      diyStore.editComponent.list[props.navIndex].goods_ids = newIds;
+    }
+  } else {
+    const newIds = calculateNewIds(diyStore.editComponent.goodsIds, tableData.value, multipleSelection.value);
+    diyStore.editComponent.goodsIds = newIds;
+  }
+  showDialog.value = false;
+};
+
+const calculateNewIds = (cacheIds: any, allPageItems: any, selectedItems: any) => {
+  // 1. 获取当前页所有存在的 ID 集合 (用于识别哪些旧数据属于当前页)
+  const currentPageIdSet = new Set(allPageItems.map((item) => item.id));
+  // 2. 获取最终选中项的 ID 集合
+  const selectedIdSet = new Set(selectedItems.map((item) => item.id));
+  // 3. 过滤旧的缓存 IDs
+  const retainedOldIds = cacheIds.filter((id) => {
+    // 情况 A: 该 ID 不在当前页数据中 (说明是其他页的数据,必须无条件保留)
+    if (!currentPageIdSet.has(id)) {
+      return true;
+    }
+    // 情况 B: 该 ID 在当前页数据中,且也在最终选中列表中 (说明用户保持了选中)
+    if (selectedIdSet.has(id)) {
+      return true;
+    }
+    // 情况 C: 该 ID 在当前页数据中,但不在最终选中列表中 (说明用户取消了选中,如 ID 4)
+    // 返回 false,将其剔除
+    return false;
+  });
+  // 4. 合并:保留的旧数据 + 当前页新选中的数据
+  // 使用 Set 去重,虽然逻辑上 retainedOldIds 和 selectedIdSet 不会有交集,但以防万一
+  const newIdsSet = new Set([...retainedOldIds, ...selectedIdSet]);
+  // 转回数组 (如果需要保持原有顺序或特定排序,可以在此处调整)
+  // 这里简单转为数组,通常建议按数字大小排序以便阅读,或者保持插入顺序
+  return Array.from(newIdsSet).sort((a, b) => a - b);
+};
+
+//选择商品分类
+const goodsClassifyChange = (res: any) => {
+  const foundNode = findNodeByKey(props.categoryOptions, res);
+  goodsClassify.value = res;
+  queryParams.topCategoryId = '';
+  queryParams.mediumCategoryId = '';
+  queryParams.bottomCategoryId = '';
+  if (foundNode.parentId == 0) {
+    queryParams.topCategoryId = foundNode.id;
+  } else if (foundNode.children) {
+    queryParams.mediumCategoryId = foundNode.id;
+  } else {
+    queryParams.bottomCategoryId = foundNode.id;
+  }
+  handleQuery();
+};
+
+// 递归查找节点的辅助函数
+const findNodeByKey = (nodes: any, key: any) => {
+  for (const node of nodes) {
+    if (node.id === key) {
+      return node;
+    }
+    if (node.children) {
+      const found = findNodeByKey(node.children, key);
+      if (found) return found;
+    }
+  }
+  return null;
+};
+
+defineExpose({
+  onOpen
+});
+</script>
+
+<style lang="scss">
+.selected {
+  line-height: 32px;
+  position: absolute;
+  left: 0px;
+}
+</style>

+ 45 - 29
src/views/diy/components/edit-many-goods-list.vue

@@ -36,32 +36,6 @@
       <div class="edit-attr-item-wrap">
         <h3 class="mb-[10px]">分组设置</h3>
         <el-form label-width="80px" class="px-[10px]">
-          <el-form-item label="数据来源">
-            <el-radio-group v-model="diyStore.editComponent.source">
-              <el-radio value="custom">自定义</el-radio>
-              <el-radio value="goods_category">商品分类</el-radio>
-            </el-radio-group>
-          </el-form-item>
-          <el-form-item label="商品分类" v-show="diyStore.editComponent.source == 'goods_category'">
-            <el-input
-              v-model.trim="diyStore.editComponent.goods_category_name"
-              placeholder="选择分类"
-              readonly
-              class="select-diy-page-input"
-              @click="firstCategoryShowDialogOpen()"
-            >
-              <template #suffix>
-                <div @click.stop="clearCategory">
-                  <el-icon v-if="diyStore.editComponent.goods_category_name">
-                    <Close />
-                  </el-icon>
-                  <el-icon v-else>
-                    <ArrowRight />
-                  </el-icon>
-                </div>
-              </template>
-            </el-input>
-          </el-form-item>
           <div v-show="diyStore.editComponent.source == 'custom'">
             <p class="text-sm text-gray-400 mb-[10px]">鼠标拖拽可调整顺序</p>
 
@@ -79,9 +53,9 @@
                 </el-form-item>
                 <el-form-item label="选择商品">
                   <el-radio-group v-model="item.source">
-                    <el-radio value="all">全部商品</el-radio>
-                    <el-radio value="category">选择分类</el-radio>
                     <el-radio value="custom">手动选择</el-radio>
+                    <el-radio value="category">选择分类</el-radio>
+                    <el-radio value="brand">选择品牌</el-radio>
                   </el-radio-group>
                 </el-form-item>
                 <el-form-item label="选择分类" v-if="item.source == 'category'">
@@ -93,7 +67,12 @@
                   </div>
                 </el-form-item>
                 <el-form-item label="手动选择" v-if="item.source == 'custom'">
-                  <goods-select-popup ref="goodsSelectPopupRef" v-model="item.goods_ids" :min="1" :max="99" />
+                  <div class="data-num" @click="openDialog(index)">
+                    <span v-if="item.goods_ids.length == 0">请选择</span>
+                    <span v-else>已选择{{ item.goods_ids.length }}个</span>
+                    <el-icon><ArrowRight /></el-icon>
+                  </div>
+                  <!-- <goods-select-popup ref="goodsSelectPopupRef" v-model="item.goods_ids" :min="1" :max="99" /> -->
                 </el-form-item>
                 <el-form-item label="图片上传" v-show="diyStore.editComponent.headStyle == 'style-3'">
                   <upload-image v-model="item.imageUrl" :limit="1" />
@@ -365,6 +344,7 @@
       <!-- 组件样式 -->
       <slot name="style"></slot>
     </div>
+    <goods-mini ref="goodsDialogRef" :categoryOptions="categoryOptions" :navIndex="navIndex" :type="'editManyGoodsList'"></goods-mini>
   </div>
 </template>
 
@@ -374,8 +354,12 @@ import useDiyStore from '@/store/modules/diy';
 import { ElTable } from 'element-plus';
 import { range } from 'lodash-es';
 import Sortable from 'sortablejs';
+import { categoryTree } from '@/api/pmsProduct/base';
 // import { getCategoryTree, getCategoryList } from '@/addon/shop/api/goods';
 // import goodsSelectPopup from '@/addon/shop/views/goods/components/goods-select-popup.vue';
+const goodsDialogRef = ref<any>(null);
+const categoryOptions = ref<any>([]);
+const navIndex = ref<any>(0);
 
 const diyStore: any = useDiyStore();
 diyStore.editComponent.ignore = ['componentBgUrl']; // 忽略公共属性
@@ -414,6 +398,28 @@ diyStore.editComponent.list.forEach((item: any) => {
   if (!item.id) item.id = diyStore.generateRandom();
 });
 
+//打开弹窗
+const openDialog = (res: any) => {
+  navIndex.value = res;
+  goodsDialogRef.value.onOpen();
+};
+
+/** 查询分类树 */
+const getCategoryTree = async () => {
+  categoryOptions.value = [];
+  const res = await categoryTree({
+    platform: diyStore.type == 1 ? 0 : diyStore.type == 2 ? 1 : diyStore.type == 3 ? 2 : diyStore.type == 4 ? 4 : 0,
+    pageNum: 1,
+    pageSize: 9999
+  });
+  const list = res.data || [];
+  categoryOptions.value = [...list];
+  categoryOptions.value.unshift({
+    id: '',
+    label: '全部'
+  });
+};
+
 // 一级商品分类
 const firstCategoryShowDialog = ref(false);
 
@@ -508,6 +514,7 @@ const categoryTable = reactive({
 });
 
 onMounted(() => {
+  getCategoryTree();
   loadCategoryTree();
 
   loadCategoryList();
@@ -693,4 +700,13 @@ defineExpose({});
   transform: rotate(90deg) !important;
   /* 提高优先级 */
 }
+.data-num {
+  width: 100%;
+  font-size: 14px;
+  display: flex;
+  align-items: center;
+  justify-content: flex-end;
+  color: var(--el-color-primary);
+  cursor: pointer;
+}
 </style>

+ 0 - 32
src/views/diy/pccomponents/edit/goodsList-edit.vue

@@ -209,20 +209,7 @@ import usePcdiyStore from '@/store/modules/pcdiy';
 import type { TableInstance } from 'element-plus';
 const diyStore = usePcdiyStore();
 const goodsDialogRef = ref<any>(null);
-const multipleTableRef = ref<TableInstance>();
-const loading = ref(false);
-const tableData = ref<any[]>([]);
-const total = ref(0);
 const cascaderProps = { multiple: true, value: 'id', label: 'label', children: 'children' };
-const queryParams = reactive({
-  pageNum: 1,
-  pageSize: 10,
-  itemName: '',
-  topCategoryId: '',
-  mediumCategoryId: '',
-  bottomCategoryId: ''
-});
-const resultList = ref<any>([]); //单页之前被选中的数据
 const categoryOptions = ref<any>([]);
 const categoryOptions1 = ref<any>([]);
 const navIndex = ref<any>(0);
@@ -231,25 +218,6 @@ onMounted(() => {
   getCategoryTree();
 });
 
-/** 获取列表 */
-const getList = async () => {
-  loading.value = true;
-  try {
-    const res = await listBase(queryParams);
-    tableData.value = res.rows || [];
-    const result = tableData.value.filter((item: any) => diyStore.editComponent.tabList[navIndex.value].goodsIds.includes(item.id));
-    resultList.value = result;
-    nextTick(() => {
-      result.forEach((item: any) => {
-        multipleTableRef.value?.toggleRowSelection(item, true);
-      });
-    });
-    total.value = res.total || 0;
-  } finally {
-    loading.value = false;
-  }
-};
-
 /** 查询分类树 */
 const getCategoryTree = async () => {
   categoryOptions.value = [];