|
@@ -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>
|