浏览代码

✨ feat: 新增新建产品线--商品模块

WanGxC 1 年之前
父节点
当前提交
a042139246

+ 4 - 3
src/main.ts

@@ -27,6 +27,7 @@ import iconfont from '/@/assets/iconfont/iconfont.json' //引入json文件
 import '/@/assets/iconfont/iconfont.css' //引入css
 // 自动注册插件
 import { scanAndInstallPlugins } from '/@/views/plugins/index'
+import naive from 'naive-ui'
 import VXETable from 'vxe-table'
 import 'vxe-table/lib/style.css'
 
@@ -55,9 +56,9 @@ iconList.addIcon(forIconfont.list) // 添加iconfont dvadmin3的icon
 iconList.addIcon(elementPlus) // 添加element plus的图标
 iconList.addIcon(fontAwesome470) // 添加fontAwesome 470版本的图标
 
-const naive = create({
-  components: [NButton],
-})
+// const naive = create({
+//   components: [NButton],
+// })
 
 let app = createApp(App)
 

+ 185 - 31
src/views/demo/index.vue

@@ -16,48 +16,202 @@
   </el-upload>
   <el-button @click="submit">上传</el-button>
 
-  <div style="padding: 0 12px">
-    <div style="display: inline-block; width: 10%">
-      <el-card shadow="never"> qweqweqwe </el-card>
-    </div>
-    <div style="display: inline-block; width: 90%">
-      <div style="display: flex; justify-content: flex-end; align-items: center">
-        <el-button>确定</el-button>
-        <el-button>确定</el-button>
-        <el-button>确定</el-button>
-        <el-button>确定</el-button>
+  <el-card>
+    <div style="display: flex">
+      <div style="width: 50%">
+        <button @click="handleSelectedItems">获取选中项</button>
+        <div class="demo-collapse">
+          <el-collapse v-model="activeNames">
+            <el-collapse-item v-for="(item, index) in data" :key="item.parentAsin" :name="String(index)">
+              <template #title>
+                <el-checkbox v-model="item.checked" @click.stop="stopOpen" @change="checkAll(item, item.checked)">{{ item.parentAsin }}</el-checkbox>
+                <el-tag style="margin-left: 8px" effect="plain" size="small" round>{{ item.num }}ASIN</el-tag>
+              </template>
+              <ul style="padding-left: 20px">
+                <li v-for="child in item.childAsin" :key="child.asin">
+                  <div style="display: flex; align-items: center; margin-bottom: 10px">
+                    <el-checkbox v-model="child.checked" @change="checkSingle(item)"></el-checkbox>
+                    <!-- <img :src="child.image" style="width: 50px; height: 50px; margin-right: 10px" /> -->
+                    <div>
+                      <span>{{ child.Title }}</span>
+                      <span>{{ child.asin }}</span>
+                    </div>
+                  </div>
+                </li>
+              </ul>
+            </el-collapse-item>
+          </el-collapse>
+        </div>
       </div>
-      <div>
-        <vxe-table round :data="tableData">
-          <vxe-column resizable type="seq" width="60"></vxe-column>
-          <vxe-column resizable field="name" title="Name"></vxe-column>
-          <vxe-column resizable field="sex" title="Sex"></vxe-column>
-          <vxe-column resizable field="age" title="Age"></vxe-column>
-        </vxe-table>
+
+      <div style="width: 50%">
+        <!-- 在右侧面板的上方或下方添加这个按钮 -->
+        <button @click="removeSelectedItems">删除选中项</button>
+        <button @click="removeAllItems">删除所有</button>
+
+        <div class="demo-collapse">
+          <el-collapse v-model="activeNames">
+            <el-collapse-item v-for="(item, index) in selectedData" :key="item.parentAsin" :name="String(index)">
+              <template #title>
+                <el-checkbox v-model="item.checked" @click.stop="stopOpen" @change="checkAll(item, item.checked)">{{ item.parentAsin }}</el-checkbox>
+                <el-tag style="margin-left: 8px" effect="plain" size="small" round>{{ item.num }}ASIN</el-tag>
+              </template>
+              <ul style="padding-left: 20px">
+                <li v-for="child in item.childAsin" :key="child.asin">
+                  <div style="display: flex; align-items: center; margin-bottom: 10px">
+                    <el-checkbox v-model="child.checked" @change="checkSingle(item)"></el-checkbox>
+                    <!-- <img :src="child.image" style="width: 50px; height: 50px; margin-right: 10px" /> -->
+                    <div>
+                      <span>{{ child.Title }}</span>
+                      <span>{{ child.asin }}</span>
+                    </div>
+                  </div>
+                </li>
+              </ul>
+            </el-collapse-item>
+          </el-collapse>
+        </div>
       </div>
     </div>
-  </div>
-  <div>
-    <p style="max-width: 100px; text-overflow: ellipsis; white-space: nowrap; display: inline-block; vertical-align: bottom; overflow: hidden;">
-      住在我心里孤独的 孤独的海怪 痛苦之王 开始厌倦 深海的光 停滞的海浪
-    </p>
-  </div>
+  </el-card>
 </template>
 
 <script lang="ts" setup>
-import { ref, onMounted } from 'vue'
+import { ref, onMounted, computed } from 'vue'
 import { useFs } from '@fast-crud/fast-crud'
 import { createCrudOptions } from './crud'
-
 import { request } from '/@/utils/service'
-
 import type { UploadProps, UploadUserFile, UploadFile, UploadFiles, UploadProgressEvent } from 'element-plus'
-const tableData = ref([
-  { id: 10001, name: 'Test1', role: 'Develop', sex: 'Man', age: 28, address: 'test abc' },
-  { id: 10002, name: 'Test2', role: 'Test', sex: 'Women', age: 22, address: 'Guangzhou' },
-  { id: 10003, name: 'Test3', role: 'PM', sex: 'Man', age: 32, address: 'Shanghai' },
-  { id: 10004, name: 'Test4', role: 'Designer', sex: 'Women', age: 24, address: 'Shanghai' },
+
+const data = ref([
+  {
+    parentAsin: '1ParentASIN',
+    checked: false,
+    childAsin: [
+      { asin: '1childASIN-1', image: 'http://xxxxxx.jpg', Title: '这是1childASIN-1', checked: false },
+      { asin: '1childASIN-2', image: 'http://xxxx.jpg', Title: '这是1childASIN-2', checked: false },
+    ],
+    num: 2,
+  },
+  {
+    parentAsin: '2ParentASIN',
+    checked: false,
+    childAsin: [
+      { asin: '2childASIN-1', image: 'http://xxxxx.jpg', Title: '这是2childASIN-1', checked: false },
+      { asin: '2childASIN-2', image: 'http://xxx.jpg', Title: '这是2childASIN-2', checked: false },
+    ],
+    num: 2,
+  },
 ])
+
+const activeNames = ref(data.value.map((_, index) => String(index)))
+
+function stopOpen() {
+  console.log(1213)
+}
+
+const checkAll = (parent, checked) => {
+  // 当选中或取消选中父级复选框时
+  parent.childAsin.forEach((child) => {
+    child.checked = checked
+  })
+}
+
+function checkSingle(parent) {
+  // 当选中或取消选中单个子项复选框时
+  const allChecked = parent.childAsin.every((child) => child.checked)
+  parent.checked = allChecked
+}
+
+function getSelectedItems() {
+  // 添加用于获取所有选中项的方法
+  const selectedItems = []
+  data.value.forEach((parentItem) => {
+    if (parentItem.checked) {
+      // 如果父项被选中,添加父项的值,并包含所有子项的完整数据
+      const children = parentItem.childAsin.map((childItem) => {
+        return { ...childItem } // 复制整个childItem对象
+      })
+      selectedItems.push({ parentAsin: parentItem.parentAsin, childAsin: children })
+    } else {
+      // 如果父项未被选中,仅添加被选中的子项的完整数据
+      const selectedChildren = parentItem.childAsin
+        .filter((childItem) => childItem.checked)
+        .map((childItem) => {
+          return { ...childItem } // 复制整个childItem对象
+        })
+      if (selectedChildren.length > 0) {
+        selectedItems.push({ parentAsin: parentItem.parentAsin, childAsin: selectedChildren })
+      }
+    }
+  })
+  return selectedItems
+}
+
+const selectedData = ref([])
+
+function handleSelectedItems() {
+  // 获取所有选中项的深拷贝并取消勾选状态
+  const newSelectedItems = getSelectedItems().map(item => ({
+    ...item,
+    checked: false, // 取消父项勾选状态
+    num: item.childAsin.length, // 更新子项数量
+    childAsin: item.childAsin.map(child => ({ ...child, checked: false })), // 取消子项勾选状态
+  }));
+
+  // 更新selectedData以包含新选中的项,如果项已存在,则合并子项,并确保不重复
+  newSelectedItems.forEach(newItem => {
+    const existingItemIndex = selectedData.value.findIndex(item => item.parentAsin === newItem.parentAsin);
+    if (existingItemIndex !== -1) {
+      // 合并子项,并确保不重复添加相同的子项
+      const existingChildren = selectedData.value[existingItemIndex].childAsin;
+      const newChildren = newItem.childAsin;
+      const mergedChildren = [...existingChildren];
+      newChildren.forEach(newChild => {
+        if (!mergedChildren.some(child => child.asin === newChild.asin)) {
+          mergedChildren.push(newChild);
+        }
+      });
+
+      // 更新现有项的子项和子项数量
+      selectedData.value[existingItemIndex].childAsin = mergedChildren;
+      selectedData.value[existingItemIndex].num = mergedChildren.length; // 更新子项数量
+    } else {
+      // 如果不存在相同的父Asin,则添加新项
+      selectedData.value.push(newItem);
+    }
+  });
+
+  // 清除原始数据的选中状态
+  clearSelections();
+}
+
+
+// 清除所有选中状态的辅助函数
+function clearSelections() {
+  data.value.forEach((parentItem) => {
+    parentItem.checked = false // 取消父项的选中状态
+    parentItem.childAsin.forEach((childItem) => {
+      childItem.checked = false // 取消子项的选中状态
+    })
+  })
+}
+
+function removeSelectedItems() {
+  // 过滤掉所有被选中的项
+  selectedData.value = selectedData.value.filter((parentItem) => {
+    // 过滤掉父项下所有被选中的子项
+    parentItem.childAsin = parentItem.childAsin.filter((childItem) => !childItem.checked)
+    // 仅保留未被完全移除的父项(即至少有一个子项未被选中)
+    return parentItem.childAsin.length > 0
+  })
+}
+
+// 删除所有selectData的数据
+function removeAllItems() {
+  selectedData.value.splice(0)
+}
+
 const fileList = ref<UploadUserFile[]>([])
 const onProgress = (evt: UploadProgressEvent, uploadFile: UploadFile, uploadFiles: UploadFiles) => {
   console.log(evt)

+ 7 - 0
src/views/productCenter/productList/api.ts

@@ -50,4 +50,11 @@ export function getAllProduct(query) {
     params: query,
   })
 }
+export function postCreateProductLine(body) {
+  return request({
+    url: '/api/sellers/productline/create/',
+    method: 'POST',
+    params: body,
+  })
+}
 

+ 19 - 9
src/views/productCenter/productList/components/AsinTable.vue

@@ -1,7 +1,12 @@
 <template>
   <div style="overflow: hidden; width: 100%; height: 600px">
     <vxe-grid v-bind="gridOptions">
-
+      <template #toolbar_buttons>
+        <span>
+          数据对比
+          <vxe-switch v-model="isCompare" size="mini" />
+        </span>
+      </template>
       <template #name_default="{ row }">
         <vxe-button type="text" @click="openDetail(row)">点击{{ row.name }}</vxe-button>
       </template>
@@ -13,18 +18,21 @@
 </template>
 
 <script setup>
-import { reactive } from 'vue'
+import { reactive, ref } from 'vue'
 import { VXETable } from 'vxe-table'
 
 const gridOptions = reactive({
-  height: "auto",
+  height: 'auto',
   border: false,
   round: true,
   columnConfig: {
-    resizable: true
+    resizable: true,
   },
   toolbarConfig: {
     custom: true,
+    slots: {
+      buttons: 'toolbar_buttons',
+    },
   },
   columns: [
     { field: 'name', title: 'Name', align: 'center', width: 130, slots: { default: 'name_default' } },
@@ -75,17 +83,19 @@ const gridOptions = reactive({
     { id: 10003, name: 'TestLast', role: 'PM', sex: '0', age: 32, num: 12, address: 'Shanghai' },
   ],
 })
-const formatSex = (row) => {
+
+function formatSex(row) {
   return row.sex === '1' ? '男' : '女'
 }
-const openDetail = (row) => {
+
+function openDetail(row) {
   VXETable.modal.message({
     status: 'success',
     content: `点击了${row.name}`,
   })
 }
-</script>
 
-<style scoped>
+const isCompare = ref(false)
+</script>
 
-</style>
+<style scoped></style>

+ 22 - 157
src/views/productCenter/productList/components/ProductLineDialog.vue

@@ -1,5 +1,5 @@
 <template>
-  <el-dialog v-model="createProductDialog" title="新建产品线" width="1000">
+  <el-dialog v-model="createProductDialog" title="新建产品线" width="1300">
     <el-form
       ref="ruleFormRef"
       class="custom-ruleForm"
@@ -10,114 +10,31 @@
       label-position="top"
       status-icon>
       <el-form-item label="产品线名称:" prop="productLine">
-        <el-input v-model="ruleForm.productLine" maxlength="150" show-word-limit />
+        <el-input v-model="ruleForm.productLine" placeholder="请输入产品线名称" maxlength="150" show-word-limit style="width: 500px" />
       </el-form-item>
-      <el-form-item label="商品:" prop="product" required>
-        <div class="product-select">
-          <div class="left-part" v-loading="infiniteLoad">
-            <el-tabs v-model="activeName">
-              <el-tab-pane label="搜索" name="search">
-                <!-- <el-input v-model="searchInp" placeholder="请输入商品名称" @input="handleSearch" class="search-input" /> -->
-                <vxe-input v-model="searchInp" placeholder="请输入商品名称" type="search" class="search-input"></vxe-input>
-                <ul v-infinite-scroll="load" class="infinite-list" style="overflow: auto">
-                  <el-tree :data="data" :props="{ label: 'label', children: 'children' }" show-checkbox>
-                    <template #default="{ node, data }">
-                      <span style="margin-right: 6px">
-                        {{ node.label }}
-                      </span>
-                      <span class="custom-tree-node" style="display: flex">
-                        <!-- 显示子节点的图片 -->
-                        <span v-if="data.imageUrl" style="width: 50px">
-                          <img :src="data.imageUrl" alt="Product Image" style="height: 50px" />
-                        </span>
-                        <el-tooltip effect="dark" :content="data.title" placement="top-start">
-                          <span class="custom-node-title">
-                            {{ data.title }}
-                          </span>
-                        </el-tooltip>
-                      </span>
-                    </template>
-                  </el-tree>
-                </ul>
-              </el-tab-pane>
-              <el-tab-pane label="输入" name="input">Config</el-tab-pane>
-            </el-tabs>
-          </div>
-          <div class="right-part"></div>
-        </div>
+      <el-form-item label="商品:" required>
+        <ProductList></ProductList>
       </el-form-item>
       <el-form-item>
         <el-button type="primary" @click="submitForm(ruleFormRef)"> 创建 </el-button>
-        <el-button @click="resetForm(ruleFormRef)">取消</el-button>
+        <el-button @click="createProductDialog = false">取消</el-button>
       </el-form-item>
     </el-form>
   </el-dialog>
 </template>
 
 <script setup lang="ts">
-import { onBeforeUnmount, onMounted, reactive, ref, inject } from 'vue'
+import { onBeforeUnmount, onMounted, reactive, ref } from 'vue'
 import emitter from '/@/utils/emitter'
 import type { FormInstance, FormRules } from 'element-plus'
-import { getAllProduct } from '../api'
+import ProductList from '../components/ProductList.vue'
+import { postCreateProductLine } from '../api'
 
-const profile = <any>inject('profile')
-
-const activeName = ref('search')
-
-// 搜索相关
-const searchInp = ref('')
-function handleSearch() {}
-
-// 树节点相关
-const infiniteLoad = ref(false)
-const data = ref([])
-let currentPage = 1
-let total = 0
-let limit = 10
-
-function transformProductsToTreeData(products) {
-  return products.map((product) => ({
-    label: product.parentAsin + ` (${product.childAsin.length} ASIN)`, // 使用parentAsin作为节点标签
-    // numChildren: product.childAsin.length, // 添加子节点的数量
-    children: product.childAsin.map((child) => ({
-      title: child.Title,
-      imageUrl: child.Image,
-    })),
-  }))
-}
-
-async function fetchAllProduct() {
-  infiniteLoad.value = true
-  const query = {
-    profile_id: profile.value.profile_id,
-    page: currentPage,
-    limit: limit,
-  }
-  try {
-    const res = await getAllProduct(query)
-    if (res && res.data) {
-      // 转换数据并更新data
-      const newData = transformProductsToTreeData(res.data)
-      if (currentPage > 1) {
-        data.value = [...data.value, ...newData] // 追加数据而不是替换
-      } else {
-        data.value = newData // 第一页数据,直接替换
-      }
-      total = res.total // 更新总条目数
-    }
-  } catch (error) {
-    console.log('error:', error)
-  } finally {
-    infiniteLoad.value = false
-  }
-}
+const createProductDialog = ref(false)
 
-function load() {
-  if (currentPage * limit < total) {
-    currentPage++
-    fetchAllProduct()
-  }
-}
+emitter.on('open-productLine-dialog', (value: any) => {
+  createProductDialog.value = value.isVisible
+})
 
 // 表单相关
 interface RuleForm {
@@ -143,80 +60,28 @@ const submitForm = async (formEl: FormInstance | undefined) => {
   })
 }
 
+async function createProductLine() {
+  const body = {}
+  try {
+    const resp = await postCreateProductLine(body)
+  } catch (error) {
+    console.log('error:', error)
+  }
+}
+
 const resetForm = (formEl: FormInstance | undefined) => {
   if (!formEl) return
   formEl.resetFields()
 }
 
-const createProductDialog = ref(false)
-emitter.on('open-productLine-dialog', (value: any) => {
-  createProductDialog.value = value.isVisible
-})
-
-onMounted(() => {
-  fetchAllProduct()
-})
-
 onBeforeUnmount(() => {
   emitter.all.clear()
 })
 </script>
 
 <style scoped>
+/* 不要删除, 否则ProductList组件的样式会错乱 */
 ::v-deep(.el-form-item__content) {
   display: block !important;
 }
-.product-select {
-  display: flex;
-  border: 1px solid #dde0eb;
-  border-radius: 4px;
-  color: #4e5969;
-}
-.left-part {
-  width: 50%;
-}
-.right-part {
-  width: 50%;
-}
-.infinite-list {
-  height: 300px;
-  padding: 0;
-  margin: 0;
-  list-style: none;
-}
-.infinite-list .infinite-list-item {
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  height: 50px;
-  background: var(--el-color-primary-light-9);
-  margin: 10px;
-  color: var(--el-color-primary);
-}
-.infinite-list .infinite-list-item + .list-item {
-  margin-top: 10px;
-}
-::v-deep(.el-tree-node__content) {
-  height: auto;
-}
-.custom-node-title {
-  max-width: 350px;
-  text-overflow: ellipsis;
-  white-space: nowrap;
-  display: inline-block;
-  vertical-align: bottom;
-  overflow: hidden;
-}
-/* Tab栏 */
-::v-deep(.el-tabs__nav-scroll) {
-  overflow: hidden;
-  margin-left: 10px;
-}
-::v-deep(.el-table__inner-wrapper::before) {
-  background-color: white;
-}
-.search-input {
-  width: 95%;
-  margin: 10px;
-}
 </style>

+ 384 - 0
src/views/productCenter/productList/components/ProductList.vue

@@ -0,0 +1,384 @@
+<template>
+  <div class="product-select">
+    <div class="left-part" v-loading="infiniteLoad">
+      <el-tabs v-model="activeName">
+        <el-tab-pane label="搜索" name="search">
+          <div style="margin: 0 10px">
+            <vxe-input v-model="searchInp" placeholder="请输入商品名称" type="search" class="search-input" />
+          </div>
+          <div class="padding-0-10">
+            <div class="list-bar">
+              <span class="padding-0-10">商品列表</span>
+              <vxe-button
+                style="position: absolute; margin: 3px; right: 0"
+                type="text"
+                status="primary"
+                content="添加"
+                icon="vxe-icon-add"
+                @click="handleSelectedItems" />
+            </div>
+          </div>
+          <ul v-infinite-scroll="load" class="infinite-list" style="overflow: auto">
+            <div>
+              <el-collapse v-model="activeNames" class="padding-0-10" style="border: none">
+                <el-collapse-item v-for="(item, index) in data" :key="item.parentAsin" :name="String(index)">
+                  <template #title>
+                    <el-checkbox v-model="item.checked" @click.stop="stopOpen" @change="checkAll(item, item.checked)">
+                      {{ item.parentAsin }}
+                    </el-checkbox>
+                    <el-tag style="margin-left: 8px" effect="plain" size="small" round>{{ item.num }}ASIN</el-tag>
+                  </template>
+                  <ul class="list-container">
+                    <li v-for="child in item.childAsin" :key="child.asin">
+                      <div class="list-content">
+                        <el-checkbox v-model="child.checked" @change="checkSingle(item)" />
+                        <img :src="child.Image" class="image-item" />
+                        <div>
+                          <el-tooltip effect="dark" :content="child.Title" placement="top-start">
+                            <span class="list-item-title">{{ child.Title }}</span>
+                          </el-tooltip>
+                          <div>
+                            <span class="item-font">${{ child.Price ? child.Price : '--' }}</span>
+                            | <span class="item-quantity">{{ child.Quantity ? '有库存' : '缺货' }}</span>
+                          </div>
+                          <div><span class="item-asin">ASIN:</span> {{ child.Asin }}</div>
+                        </div>
+                      </div>
+                    </li>
+                  </ul>
+                </el-collapse-item>
+              </el-collapse>
+            </div>
+          </ul>
+        </el-tab-pane>
+        <el-tab-pane label="输入" name="input">
+          <div style="padding: 15px 20px">
+            <el-input
+              disabled="true"
+              v-model="textarea"
+              style="width: 100%"
+              :rows="15"
+              type="textarea"
+              placeholder="请输入ASIN, 多个ASIN使用逗号、空格或换行符分隔" />
+            <div style="display: flex">
+              <el-button style="flex-direction: row-reverse" :disabled="!textarea" type="primary" text bg>添加</el-button>
+            </div>
+          </div>
+        </el-tab-pane>
+      </el-tabs>
+    </div>
+    <div class="right-part">
+      <div>
+        <div class="right-top-part">
+          <span>已添加: {{ selectedData.length }}</span>
+          <span>
+            <vxe-button
+              v-if="hasSelectedItems"
+              type="text"
+              status="warning"
+              content="删除选中项"
+              icon="vxe-icon-delete"
+              @click="removeSelectedItems"></vxe-button>
+            <vxe-button type="text" status="danger" content="删除所有" icon="vxe-icon-delete" @click="removeAllItems"></vxe-button>
+          </span>
+        </div>
+        <el-scrollbar height="540px">
+          <el-collapse v-model="activeNames" class="padding-0-10" style="border: none">
+            <el-collapse-item v-for="(item, index) in selectedData" :key="item.parentAsin" :name="String(index)">
+              <template #title>
+                <el-checkbox v-model="item.checked" @click.stop="stopOpen" @change="checkAll(item, item.checked)">{{ item.parentAsin }}</el-checkbox>
+                <el-tag style="margin-left: 8px" effect="plain" size="small" round>{{ item.num }}ASIN</el-tag>
+              </template>
+              <ul class="list-container">
+                <li v-for="child in item.childAsin" :key="child.asin">
+                  <div class="list-content">
+                    <el-checkbox v-model="child.checked" @change="checkSingle(item)"></el-checkbox>
+                    <img :src="child.Image" class="image-item" />
+                    <div>
+                      <el-tooltip effect="dark" :content="child.Title" placement="top-start">
+                        <span class="list-item-title">{{ child.Title }}</span>
+                      </el-tooltip>
+                      <div>
+                        <span class="item-font">${{ child.Price ? child.Price : '--' }}</span>
+                        | <span class="item-quantity">{{ child.Quantity ? '有库存' : '缺货' }}</span>
+                      </div>
+                      <div><span class="item-asin">ASIN:</span> {{ child.Asin }}</div>
+                    </div>
+                  </div>
+                </li>
+              </ul>
+            </el-collapse-item>
+          </el-collapse>
+        </el-scrollbar>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { computed, inject, onBeforeUnmount, onMounted, ref } from 'vue'
+import { getAllProduct } from '../api'
+import emitter from '/@/utils/emitter'
+
+const profile = <any>inject('profile')
+const activeName = ref('search')
+
+const searchInp = ref('')
+const textarea = ref('')
+function handleSearch() {}
+
+const data = ref([])
+const selectedData = ref([])
+const activeNames = ref([])
+const infiniteLoad = ref(false)
+let currentPage = 1
+let total = 0
+let limit = 10
+
+function load() {
+  if (currentPage * limit < total) {
+    currentPage++
+    fetchAllProduct()
+  }
+}
+
+async function fetchAllProduct() {
+  infiniteLoad.value = true
+  const query = {
+    profile_id: profile.value.profile_id,
+    page: currentPage,
+    limit: limit,
+  }
+  try {
+    const res = await getAllProduct(query)
+    if (res && res.data) {
+      // 转换数据并更新data
+      const newData = res.data
+      if (currentPage > 1) {
+        data.value.push(...newData) // 追加数据而不是替换
+      } else {
+        data.value = newData // 第一页数据,直接替换
+      }
+      total = res.total
+      console.log('请求的数据', data.value)
+    }
+  } catch (error) {
+    console.log('error:', error)
+  } finally {
+    infiniteLoad.value = false
+    activeNames.value = data.value.map((_, index) => String(index))
+  }
+}
+
+// 当选中或取消选中父级复选框时
+function checkAll(parent, checked) {
+  parent.childAsin.forEach((child) => {
+    child.checked = checked
+  })
+}
+
+// 当选中或取消选中单个子项复选框时
+function checkSingle(parent) {
+  const allChecked = parent.childAsin.every((child) => child.checked)
+  parent.checked = allChecked
+}
+
+// 添加所有选中的项
+function getSelectedItems() {
+  const selectedItems = []
+  data.value.forEach((parentItem) => {
+    if (parentItem.checked) {
+      // 如果父项被选中,添加父项的值,并包含所有子项的完整数据
+      const children = parentItem.childAsin.map((childItem) => {
+        return { ...childItem } // 复制整个childItem对象
+      })
+      selectedItems.push({ parentAsin: parentItem.parentAsin, childAsin: children, num: parentItem.num })
+    } else {
+      // 如果父项未被选中,仅添加被选中的子项的完整数据
+      const selectedChildren = parentItem.childAsin
+        .filter((childItem) => childItem.checked)
+        .map((childItem) => {
+          return { ...childItem } // 复制整个childItem对象
+        })
+      if (selectedChildren.length > 0) {
+        selectedItems.push({ parentAsin: parentItem.parentAsin, childAsin: selectedChildren, num: selectedChildren.length })
+      }
+    }
+  })
+  return selectedItems
+}
+
+// 获取所有选中项的深拷贝并取消勾选状态
+function handleSelectedItems() {
+  const newSelectedItems = getSelectedItems().map((item) => ({
+    ...item,
+    checked: false, // 取消父项勾选状态
+    num: item.childAsin.length, // 更新子项数量
+    childAsin: item.childAsin.map((child) => ({ ...child, checked: false })), // 取消子项勾选状态
+  }))
+
+  // 更新selectedData以包含新选中的项,如果项已存在,则合并子项,并确保不重复
+  newSelectedItems.forEach((newItem) => {
+    const existingItemIndex = selectedData.value.findIndex((item) => item.parentAsin === newItem.parentAsin)
+    if (existingItemIndex !== -1) {
+      // 合并子项,并确保不重复添加相同的子项
+      const existingChildren = selectedData.value[existingItemIndex].childAsin
+      const newChildren = newItem.childAsin
+      const mergedChildren = [...existingChildren]
+      newChildren.forEach((newChild) => {
+        if (!mergedChildren.some((child) => child.asin === newChild.asin)) {
+          mergedChildren.push(newChild)
+        }
+      })
+
+      // 更新现有项的子项和子项数量
+      selectedData.value[existingItemIndex].childAsin = mergedChildren
+      selectedData.value[existingItemIndex].num = mergedChildren.length // 更新子项数量
+    } else {
+      // 如果不存在相同的父Asin,则添加新项
+      selectedData.value.push(newItem)
+    }
+  })
+
+  clearSelections()
+}
+
+// 清除所有选中状态的辅助函数
+function clearSelections() {
+  data.value.forEach((parentItem) => {
+    parentItem.checked = false // 取消父项的选中状态
+    parentItem.childAsin.forEach((childItem) => {
+      childItem.checked = false // 取消子项的选中状态
+    })
+  })
+}
+
+function removeAllItems() {
+  selectedData.value.splice(0)
+}
+
+function removeSelectedItems() {
+  selectedData.value = selectedData.value.filter((parentItem) => {
+    // 过滤掉父项下所有被选中的子项
+    parentItem.childAsin = parentItem.childAsin.filter((childItem) => !childItem.checked)
+    // 仅保留未被完全移除的父项(即至少有一个子项未被选中)
+    return parentItem.childAsin.length > 0
+  })
+}
+
+// 阻止点击选择框时打开折叠面板
+function stopOpen() {
+  // console.log(1213)
+}
+
+// 判断是否有选中的项 给模板提供用来判断是否显示删除已选中的按钮
+const hasSelectedItems = computed(() => {
+  return selectedData.value.some((parentItem) => {
+    return parentItem.childAsin.some((childItem) => childItem.checked)
+  })
+})
+
+onMounted(() => {
+  fetchAllProduct()
+})
+</script>
+
+<style scoped>
+.product-select {
+  display: flex;
+  border: 1px solid #dde0eb;
+  border-radius: 4px;
+  color: #4e5969;
+}
+.left-part {
+  width: 50%;
+  border-right: 1px solid #e5e7ec;
+}
+.right-part {
+  width: 50%;
+}
+.right-top-part {
+  height: 40px;
+  padding: 0 10px;
+  border-top-right-radius: 4px;
+  background-color: #f5f5f5;
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+.infinite-list {
+  height: 458px;
+  padding: 0;
+  margin: 0;
+  list-style: none;
+}
+.infinite-list .infinite-list-item {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  height: 50px;
+  background: var(--el-color-primary-light-9);
+  margin: 10px;
+  color: var(--el-color-primary);
+}
+.infinite-list .infinite-list-item + .list-item {
+  margin-top: 10px;
+}
+.list-item-title {
+  font-weight: 500;
+  color: #1d2129;
+  overflow: hidden;
+  display: -webkit-box;
+  -webkit-box-orient: vertical;
+  -webkit-line-clamp: var(--line-clamp);
+  white-space: pre-wrap;
+  --line-clamp: 1;
+}
+/* Tab栏 */
+::v-deep(.el-tabs__nav-scroll) {
+  overflow: hidden;
+  margin-left: 10px;
+}
+::v-deep(.el-table__inner-wrapper::before) {
+  background-color: white;
+}
+.search-input {
+  width: 100%;
+  margin: 10px 0;
+}
+.list-content {
+  display: flex;
+  align-items: center;
+  margin-bottom: 10px;
+}
+.image-item {
+  width: 50px;
+  height: 50px;
+  margin: 0 5px;
+}
+.list-bar {
+  width: 100%;
+  height: 30px;
+  background-color: #f5f5f5;
+  position: relative;
+}
+.list-container {
+  padding-left: 20px;
+}
+.padding-0-10 {
+  padding: 0 10px;
+}
+.item-asin {
+  color: #6b7785;
+}
+.item-font {
+  font-weight: 600;
+}
+.item-quantity {
+  color: #6b7785;
+}
+/* 折叠面板底部间距 */
+::v-deep(.el-collapse-item__content) {
+  padding-bottom: 0;
+}
+</style>