Эх сурвалжийг харах

feat: 创建订单产品选择,支持卡片下拉UI

cuiyalong 1 сар өмнө
parent
commit
365ddc5bc7

+ 1 - 0
src/views/create-order/components/ProductInfoCard.vue

@@ -10,6 +10,7 @@
             :loading="loading"
             :showLoading="true"
             checkPower
+            useCardPopover
             @input="onProductionInput"
             @change="onProductionChange"
           />

+ 19 - 1
src/views/create-order/components/product-info-submodule/ProductTypeSelector.vue

@@ -1,7 +1,17 @@
 <template>
   <div class="product-type-selector-container">
     <el-form-item label="选择产品" required :error="productTypeError">
+      <SelectProductCard
+        v-if="useCardPopover"
+        :options="powerProductTypeOptions"
+        class="product-type-cascader"
+        v-model="productType1"
+        @change="firstTypeChange"
+        useElementOutput
+        :disabled="activityMark"
+        :clearable="clearable"></SelectProductCard>
       <el-cascader
+        v-else
         :options="powerProductTypeOptions"
         class="product-type-cascader"
         popper-class="product-type-cascader-popper"
@@ -45,16 +55,24 @@ import { productTypeOptions2 } from '@/views/create-order/data/index.js'
 import { ActivityProductName } from '@/views/create-order/data'
 import { cloneDeep } from 'lodash'
 import { productKeyMap } from '@/views/create-order/data'
-
+import SelectProductCard from '@/views/create-order/components/product-info-submodule/SelectProductCard'
 
 export default {
   name: 'ProductTypeSelector',
+  components: {
+    SelectProductCard,
+  },
   props: {
     // 检查是否有显示权限
     checkPower: {
       type: Boolean,
       default: false,
     },
+    // 是否使用卡片下拉(默认false使用级联下拉)
+    useCardPopover: {
+      type: Boolean,
+      default: false,
+    },
     collapseTags: {
       type: Boolean,
       default: false,

+ 310 - 0
src/views/create-order/components/product-info-submodule/SelectProductCard.vue

@@ -0,0 +1,310 @@
+<template>
+  <el-select
+    :value="valueText"
+    popper-class="product-type-cascader-popper"
+    class="select-product-card-cascader"
+    size="medium"
+    ref="selectCascader"
+    :popper-append-to-body="false"
+    :placeholder="placeholder"
+    :disabled="disabled">
+      <template #empty>
+        <div class="select-list-container">
+          <div
+            class="select-list-row"
+            v-for="(row, index) in renderOptions"
+            :key="index">
+            <div class="select-list-label">{{ row.label }}:</div>
+            <div class="select-list-content product-list" v-if="row.children && row.children.length > 0">
+              <button
+                class="product-button"
+                :class="{ active: product.selected }"
+                v-for="product in row.children"
+                :key="product.code"
+                @click.stop.prevent="clickButton(product)"
+              >{{ product.label }}</button>
+            </div>
+          </div>
+        </div>
+      </template>
+  </el-select>
+</template>
+
+<script>
+export default {
+  name: 'SelectProductCard',
+  props: {
+    useElementOutput: {
+      type: Boolean,
+      default: false
+    },
+    disabled: {
+      type: Boolean,
+      default: false
+    },
+    placeholder: {
+      type: String,
+      default: '请选择产品'
+    },
+    value: {
+      type: Array,
+      default() {
+        return []
+      }
+    },
+    options: {
+      type: Array,
+      default() {
+        return [
+          // {
+          //   label:'label1',
+          //   value: 'value1',
+          //   children: [
+          //     {
+          //       label:'label1',
+          //       value: 'value1',
+          //     },
+          //     {
+          //       label: 'label2',
+          //       value: 'value2',
+          //     },
+          //   ]
+          // },
+          // {
+          //   label: 'label2',
+          //   value: 'value2',
+          // },
+        ]
+      }
+    },
+  },
+  computed: { 
+    valueText() {
+      if (this.useElementOutput) {
+        if (Array.isArray(this.value)) {
+          if (this.value.length > 1) {
+            const code = this.value[1]
+            const codeName = this.findProductName(code)
+            return [this.value[0], codeName].join(' / ')
+          } else {
+            return this.value.join(' / ')
+          }
+        } else {
+          return ''
+        }
+      } else {
+        const codeArr = this.value
+        if (Array.isArray(codeArr)) {
+          const arr = []
+          codeArr.forEach(code => {
+            const parentName = this.getParentNameWithCode(code)
+            const codeName = this.findProductName(code)
+            arr.push([parentName, codeName].join(' / '))
+          })
+          return arr.join('、')
+        } else {
+          return ''
+        }
+      }
+    },
+    renderOptions() {
+      return this.initRenderOptions(this.options)
+    }
+  },
+  watch: {
+    value: {
+      deep: true,
+      handler(n) {
+        this.setState(n)
+      },
+    },
+  },
+  methods: {
+    // 初始化数据结构
+    initRenderOptions(options) {
+      return options.map(p => { 
+        return {
+          ...p,
+          children: p.children.map(c => {
+            return {
+              selected: false,
+              ...c,
+            }
+          })
+        }
+      })
+    },
+    // 设置所有选项的状态
+    setAllState(f = false) {
+      this.renderOptions.forEach(p => {
+        if (Array.isArray(p.children)) {
+          p.children.forEach(c => {
+            c.selected = f
+          })
+        }
+      })
+    },
+    clickButton(product) {
+      // 取消全部选中
+      this.setAllState(false)
+      // 当前选中
+      product.selected = true
+      this.closePopover()
+      this.onChange()
+    },
+    closePopover() {
+      const c = this.$refs.selectCascader
+      c?.handleClose()
+    },
+    // 在商品列表中(排除最近使用)根据code查找某个商品
+    findProductItem(code) {
+      const withoutRecentlyUsedProductList = this.getProductListWithoutRecentlyUsedList()
+      return withoutRecentlyUsedProductList.find(product => code.includes(product.code))
+    },
+    // 获取商品列表(排除最近使用)
+    getProductListWithoutRecentlyUsedList() {
+      const withoutRecentlyUsed = this.renderOptions.filter(r => !r._recentlyUsed).map(r => {
+        if (Array.isArray(r.children) && r.children.length > 0) {
+          return r.children
+        } else {
+          return []
+        }
+      }).flat()
+      return withoutRecentlyUsed
+    },
+    getAllProductList() {
+      return this.renderOptions.map(r => {
+        if (Array.isArray(r.children) && r.children.length > 0) {
+          return r.children
+        } else {
+          return []
+        }
+      }).flat()
+    },
+    // 从商品列表中查找商品名称
+    findProductName(code) {
+      const codeItem = this.findProductItem(code)
+      if (codeItem) {
+        return codeItem.label
+      } else {
+        return ''
+      }
+    },
+    getState() {
+      if (this.useElementOutput) {
+        return this.getStateForElementOutput()
+      } else {
+        return this.getStateOutput()
+      }
+    },
+    // 根据code获取1级name
+    getParentNameWithCode(code) {
+      const t = this.renderOptions.filter(r => !r._recentlyUsed).find(r => {
+        if (Array.isArray(r.children) && r.children.length > 0) {
+          return r.children.find(c => code === c.code)
+        } else {
+          return false
+        }
+      })
+      if (t) {
+        return t.name || t.label
+      } else {
+        return ''
+      }
+    },
+    getStateForElementOutput() {
+      const allProductList = this.getAllProductList()
+      const selectedItem = allProductList.find(p => p.selected)
+      if (selectedItem) {
+        const code = selectedItem.code
+        const parentName = this.getParentNameWithCode(code)
+        return [parentName, code]
+      } else {
+        return []
+      }
+    },
+    getStateOutput() {
+      const allProductList = this.getAllProductList()
+      return allProductList.filter(p => p.selected).map(p => p.code)
+    },
+    setState(e) {
+      if (this.useElementOutput) {
+        this.setStateForElementOutput(e)
+      } else{
+        this.setStateOutput(e)
+      }
+    },
+    setStateForElementOutput(e) {
+      if (!e) return
+      if (!Array.isArray(e)) return
+      const code = e[1]
+      if (code) {
+        this.setStateOutput([code])
+      }
+    },
+    setStateOutput(e) {
+      if (!e) return
+      if (!Array.isArray(e)) return
+      this.renderOptions.forEach(r => {
+        if (Array.isArray(r.children) && r.children.length > 0) {
+          r.children.forEach(c => {
+            c.selected = e.includes(c.code)
+          })
+        }
+      })
+    },
+    onChange() {
+      const inputEmit = this.getState()
+      this.$emit('input', inputEmit)
+
+      const codeArr = this.getStateOutput()
+      const infoObj = Array.isArray(codeArr) && codeArr.length > 0 ? codeArr.join(',') : ''
+      const changeEmit = {
+        ...inputEmit,
+        info: infoObj || {}
+      }
+      this.$emit('change', changeEmit)
+    },
+    firstTypeChange() {},
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.select-list-container {
+  .product-button {
+    padding: 2px 8px;
+    margin-bottom: 6px;
+    border-radius: 4px;
+    border: none;
+    outline: none;
+    text-align: left;
+    cursor: pointer;
+    &:not(:last-of-type) {
+      margin-right: 8px;
+    }
+    &.active {
+      color: $main;
+      background-color: $color_main_background;
+    }
+  }
+
+
+  .select-list-row {
+    padding: 8px 16px 2px;
+    display: flex;
+    line-height: 26px;
+    &:not(:last-of-type) {
+      border-bottom: 1px solid #eee;
+    }
+
+    .select-list-label {
+      width: 76px;
+      line-height: 30px;
+    }
+    .select-list-content {
+      flex: 1;
+    }
+  }
+}
+</style>