vue 商品sku新增,笛卡爾演算法,商品新增。動態生成table,table新增值後 再生成的table 不改變table之前輸入的值

开江鱼gty發表於2024-04-22

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>快速入門</title>
        <!-- 引入元件庫 -->
        <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
        <style type="text/css">
            .Multiple-specifications {
                margin: 18px 0 0 0;
            }

            .Specification-list {
                margin: 18px 0 0 0;
            }

            .img_marsk {
                width: 80px;
                height: 80px;
                border-radius: 5px;
                background-color: rgba(0, 0, 0, 0.7);
                position: absolute;
                z-index: 999999;
                top: 0px;
                left: 0;
                display: flex;
                justify-content: center;
                align-items: center;
            }

            .checkout_icon {
                padding: 3px;
                display: inline-block;
                font-size: 16px;
                margin-right: 10px;
                ;
                text-align: center;
                position: relative;
                border-radius: 2px;
                cursor: pointer;
            }
        </style>
    </head>
    <body>
        <div id="app">
            <div>
                <div>
                    <!-- 多規格 -->
                    <div class="Multiple-specifications">
                        <el-card title="多規格" style="border-radius: 10px;">
                            <div style="display: flex;flex-flow: row wrap;">
                                <div v-for="(item, index) in dragData" :key="index">
                                    <div label="規格名" :rules="{required: true, message: '請輸入規格名',trigger: 'blur'}">
                                        <div>
                                            <el-input v-model="item.title" placeholder="規格名" style="width:200px"
                                                @change="makenewTabel(item, 'ruleName', '')" ></el-input>
                                            <el-button @click="deletRow(index, item)">刪除</el-button>
                                        </div>
                                    </div>
                                    <div label="規格值" :rules="{required: true, message: '請輸入規格值',trigger: 'blur'}">
                                        <div v-for="(it, ix) in item.num" :key="ix" style="margin-left: 20px;">
                                            <div>
                                                <el-input v-model="it.value" placeholder="規格值" style="width:200px"
                                                    @change="makenewTabel(item, 'value', it)" ></el-input>
                                                <el-button @click="deletNum(ix, it, item, index)">刪除</el-button>
                                            </div>
                                        </div>
                                    </div>
                                    <div @click="addSku(index)">+新增規格值</div>
                                </div>
                            </div>
                            <div @click="addOtherSku">+新增其他規格
                            </div>
                        </el-card>
                    </div>
                    <!-- 規格列表  -->
                    <div class="Specification-list">
                        <el-card title="規格列表" style="border-radius: 10px;">
                            <el-table :data="duoTableData">
                                <el-table-column v-for="(val, key) in columns2" :key="key" :prop="val.dataIndex" :label="val.title">
                                    <template slot-scope="scope">
                                        <el-input placeholder="請輸入" v-model="scope.row[val.dataIndex]" @blur="emitTableData"></el-input>
                                    </template>
                                </el-table-column>
                            </el-table>
                        </el-card>
                    </div>
                </div>
            </div>
        </div>
    </body>
    <!-- 引入vue mete -->
    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
    <script src="https://cdn.bootcss.com/vue/2.6.11/vue.js"></script>
    <!-- import JavaScript -->
    <script src="https://cdn.bootcss.com/axios/0.19.0-beta.1/axios.js"></script>
    <script src="https://unpkg.com/element-ui/lib/index.js"></script>
    <script>
        new Vue({
            el: '#app',

            data() {
                return {
                    tableData:[],
                    duoTableData: [],
                    dragData: [],
                    columns2: [],
                    columns: [],
                    specificationListdata: [],
                }
            },
            created() {
                this.initDrag()
                this.columns = [
                    {
                        title: `售價(US$})`,
                        dataIndex: 'salesPrice',
                    },
                    {
                        title: `原價(US$})`,
                        dataIndex: 'originalPrice',
                    },
                    {
                        title: '重量',
                        width: '180',
                    },
                    {
                        title: '庫存數量',
                        dataIndex: 'goodsStock',
                    },
                    {
                        title: 'SKU(貨號)',
                        dataIndex: 'skuNo',
                    },
                    {
                        title: '條形碼',
                        dataIndex: 'barCode',
                    },
                    {
                        title: '操作',
                        dataIndex: 'action',
                    }
                ]
                    this.resetColumns()
            },
            methods: {
                // 重置表頭
                /***
                 * dragData的預設資料
                 */
                initDrag() {
                    this.dragData = this.tableData.length > 0 ? JSON.parse(JSON.stringify(this.tableData)) : [{
                        title: '',
                        oldTitle: '',
                        num: [{
                            value: '',
                            oldValue: ''
                        }]
                    }]
                    // 如果是新增取消確定 // 或者單規格,就要清空表頭and 表格資料
                        // 把old 也要清空
                        this.duoTableData = []
                },
                /**
                 * 得到列
                 */
                resetColumns() {
                    const rules = []
                    for (var j = 0; j < this.dragData.length; j++) {
                        const obj = {}
                        obj.title = this.dragData[j].title
                        obj.dataIndex = `newHead${obj.title}`
                        rules.push(obj)
                    }
                    const columns = [...this.columns]
                    columns.splice(1, 0, ...rules)
                    this.columns2 = columns
                },
                async deletRow(index, item) {
                    if (item.title) {
                        const ret = await this.$confirm(`確定要刪除 ${item.title} 規格?`)
                        if (!ret) {
                            return false
                        }
                    }
                    this.dragData.splice(index, 1)
                    this.tableData = this.dragData
                    this.makenewTabel(item, 'deleteRule', index)
                },
                async deletNum(index, ix, item, iii) {
                    if (item.num < 1) {
                        this.$message.error('必須有一個規格值', 2)
                        return false
                    }
                    if (ix.value) {
                        let title = `確定要刪除 ${item.title} 規格中的 ${ix.value}?`
                        if (!item.title) {
                            title = `確定要刪除 ${ix.value} 規格值?`
                        }
                        const ret = await this.$confirm(title)
                        if (!ret) {
                            return false
                        }
                    }
                    this.dragData[iii].num.splice(index, 1)
                    this.makenewTabel(item, 'deleteRule', ix)
                },
                addSku(index) {
                    this.dragData[index].num.push({
                        value: '',
                        oldValue: ''
                    })
                },
                addOtherSku() {
                    this.dragData.push({
                        title: '',
                        oldTitle: '',
                        num: [{
                            value: '',
                            oldValue: ''
                        }]
                    })
                },
                /** 按規格得到笛卡爾乘積列表 handleList */
                getDecareList() {
                    const ret = []
                    if (this.dragData.length === 0) {
                        return ret
                    } else if (this.dragData.length === 1) {
                        for (var m = 0; m < this.dragData[0].num.length; m++) {
                            const e = {}
                            e[`newHead${this.dragData[0].title}`] = this.dragData[0].num[m].value
                            e['weightUnit'] = 'g'
                            e['goodsStock'] = 0
                            ret.push(e)
                        }
                        return ret
                    }
                    // 展開table中的資料
                    const arr1 = this.dragData.map((item) => {
                        const res = []
                        item.num.forEach(v => {
                            res.push({
                                value: v.value,
                                ruleName: item.title
                            })
                        })
                        return res
                    })
                    // 構造笛卡爾乘積
                    const r = arr1.reduce((col, row) => {
                        const res = []
                        col.forEach(c => {
                            row.forEach(r => {
                                const t = Array.isArray(c) ? [...c] : [`#${c.ruleName}#${c.value}`]
                                t.push(`#${r.ruleName}#${r.value}`)
                                res.push(t)
                            })
                        })
                        return res
                    })
                    const pattern = new RegExp('#([^#]+)#(.*)')
                    let match = []

                    for (var i = 0; i < r.length; i++) {
                        const e = {}
                        for (var k = 0; k < r[i].length; k++) {
                            match = pattern.exec(r[i][k])
                            if (match) {
                                e[`newHead${match[1]}`] = match[2]
                                e['weightUnit'] = 'g'
                                e['goodsStock'] = 0
                            }
                        }
                        ret.push(e)
                    }
                    return ret
                },
                /*** 規格生成  */
                makenewTabel(item, type, value) {
                    this.resetColumns()
                    // 深複製一個值
                    const copyListData = JSON.parse(`${JSON.stringify(this.duoTableData)}`)
                    // 得到笛卡爾列
                    const specificationListdata = this.getDecareList()
                    const oldDataList = {}
                    let speckey = []
                    // 原值
                    let key = ''
                    let title = ''
                    // 得到規格名用於data中舊的規格資訊
                    const ruleNames = this.dragData.map(table => {
                        return `newHead${table.title}`
                    })
                    copyListData.forEach(data => {
                        speckey = []
                        this.dragData.forEach(table => {
                            // 值變化
                            title = `newHead${table.title}`
                            key = data[title]
                            if (!key) {
                                if (type === 'value') {
                                    data[title] = value.value
                                    key = value.value
                                }
                            }
                            if (type === 'value' && table === item && key === value.oldValue) {
                                data[`newHead${table.title}`] = value.value
                                key = value.value
                            } else {
                                if (type === 'ruleName' && table === item) {
                                    data[`newHead${table.title}`] = data[`newHead${table.oldTitle}`]
                                    key = data[`newHead${table.oldTitle}`]
                                }
                            }
                            speckey.push(key)
                        })
                        // 刪除原來的舊列原來的舊值
                        Object.keys(data).forEach(key => {
                            if (key.startsWith('newHead') && !ruleNames.includes(key)) {
                                delete data[key]
                            }
                        })
                        oldDataList[speckey.join('-')] = data
                    })
                    // 新值
                    const temps = specificationListdata
                    temps.forEach((data, index) => {
                        speckey = []
                        this.dragData.forEach(table => {
                            speckey.push(data[`newHead${table.title}`])
                        })
                        key = speckey.join('-')
                        if (oldDataList[key]) {
                            temps[index] = oldDataList[key]
                        }
                    })
                    this.duoTableData = temps
                    if (type !== 'reset') {
                        if (type === 'value') {
                            value.oldValue = value.value
                        } else {
                            item.oldTitle = item.title
                        }
                    }
                },
                // 每次失去焦點後,把值emit
                emitTableData() {
                    const emitData = {
                        tableData: this.tableData,
                        specificationListdata: this.specificationListdata
                    }
                },
            }

        });
    </script>
</html>

相關文章