|
@@ -0,0 +1,391 @@
|
|
|
+<template>
|
|
|
+ <div>
|
|
|
+ <div v-if="patternData">
|
|
|
+ <div class="attr__box">
|
|
|
+ <div class="attr__list" v-if="!value.id">
|
|
|
+ <div class="item" v-for="(attr, index) in patternData" :key="index">
|
|
|
+ <div class="attr__title">
|
|
|
+ <div class="attr__name">{{attr.name}}</div>
|
|
|
+ <Input
|
|
|
+ class="attr__input"
|
|
|
+ v-if="attr.hand_add_status"
|
|
|
+ v-model="attr.text"
|
|
|
+ icon="md-add-circle"
|
|
|
+ @on-enter="addAttr(attr.text, index)"
|
|
|
+ @on-click="addAttr(attr.text, index)"></Input>
|
|
|
+ </div>
|
|
|
+ <div class="attr__item">
|
|
|
+ <CheckboxGroup v-model="attr.selected" @on-change="onCheckGroupChange">
|
|
|
+ <Checkbox
|
|
|
+ class="tag"
|
|
|
+ v-for="(value, valueIndex) in attr.list"
|
|
|
+ :key="valueIndex"
|
|
|
+ :label="value">
|
|
|
+ <button class="close">
|
|
|
+ <Icon
|
|
|
+ size="20"
|
|
|
+ color="#ed4014"
|
|
|
+ type="md-close-circle"
|
|
|
+ v-on:click.stop.capture="remove(attr, valueIndex)" />
|
|
|
+ </button>
|
|
|
+ <span style="user-select: none;">{{value}}</span>
|
|
|
+ </Checkbox>
|
|
|
+ </CheckboxGroup>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="attr__table" v-if="tableData.tableHead.length > 5">
|
|
|
+ <div class="thead">
|
|
|
+ <div class="tr">
|
|
|
+ <div class="th" v-for="(head, headIndex) in tableData.tableHead" :key="headIndex">{{head}}</div>
|
|
|
+ </div>
|
|
|
+ </div class="thead">
|
|
|
+ <div class="tbody">
|
|
|
+ <div
|
|
|
+ v-for="(body, bodyIndex) in tableData.tableBody"
|
|
|
+ :key="bodyIndex"
|
|
|
+ class="tr"
|
|
|
+ :class="{ 'disabled': body.invisible }">
|
|
|
+ <div class="td" v-for="(value, valueIndex) in body.value" :key="valueIndex">
|
|
|
+ {{value}}
|
|
|
+ </div>
|
|
|
+ <div class="td">
|
|
|
+ <InputNumber
|
|
|
+ :disabled="!!body.invisible"
|
|
|
+ v-model="values[body.id].price"
|
|
|
+ :min="0"
|
|
|
+ size="small"
|
|
|
+ @on-change="onValueChange" />
|
|
|
+ </div>
|
|
|
+ <div class="td">
|
|
|
+ <InputNumber
|
|
|
+ :disabled="!!body.invisible"
|
|
|
+ v-model="values[body.id].stock"
|
|
|
+ :min="0"
|
|
|
+ :precision="0"
|
|
|
+ size="small"
|
|
|
+ @on-change="onValueChange" />
|
|
|
+ </div>
|
|
|
+ <div class="td">
|
|
|
+ <InputNumber
|
|
|
+ :disabled="!!body.invisible"
|
|
|
+ v-model="values[body.id].cost_price"
|
|
|
+ :min="0"
|
|
|
+ size="small"
|
|
|
+ @on-change="onValueChange" />
|
|
|
+ </div>
|
|
|
+ <div class="td">
|
|
|
+ <InputNumber
|
|
|
+ :disabled="!!body.invisible"
|
|
|
+ v-model="values[body.id].origin_price"
|
|
|
+ :min="0"
|
|
|
+ size="small"
|
|
|
+ @on-change="onValueChange" />
|
|
|
+ </div>
|
|
|
+ <div class="td">
|
|
|
+ <Button
|
|
|
+ size="small"
|
|
|
+ :type="values[body.id].is_main ? 'primary' : 'default'"
|
|
|
+ :disabled="!!values[body.id].invisible"
|
|
|
+ @click="onMainChange(body.id)">主规格</Button>
|
|
|
+ <Button size="small" @click="onHidden(body.id, values[body.id].invisible)">
|
|
|
+ {{ values[body.id].invisible ? '恢复' : '隐藏' }}
|
|
|
+ </Button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <error :text="error[data.keyword]" />
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+<script>
|
|
|
+export default {
|
|
|
+ props: ['data', 'value', 'option', 'error'],
|
|
|
+ computed: {
|
|
|
+ patternData () {
|
|
|
+ return this.value.patternData
|
|
|
+ },
|
|
|
+ },
|
|
|
+ data () {
|
|
|
+ return {
|
|
|
+ products: [],
|
|
|
+ tableData: {
|
|
|
+ tableHead: [],
|
|
|
+ tableBody: [],
|
|
|
+ },
|
|
|
+ values: {},
|
|
|
+ }
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ addAttr (v, index) {
|
|
|
+ if (!v.trim()) return
|
|
|
+ this.patternData[index].list.push(v)
|
|
|
+ this.patternData[index].text = ''
|
|
|
+ },
|
|
|
+ remove (attr, valueIndex) {
|
|
|
+ const removeItem = attr.list[valueIndex]
|
|
|
+ const selectedIndex = attr.selected.indexOf(removeItem)
|
|
|
+ if (selectedIndex !== -1) attr.selected.splice(selectedIndex, 1)
|
|
|
+ attr.list.splice(valueIndex, 1)
|
|
|
+ this.getTable()
|
|
|
+ },
|
|
|
+ onCheckGroupChange (e) {
|
|
|
+ this.getTable()
|
|
|
+ },
|
|
|
+ cartesianProduct (array) {
|
|
|
+ if (array.length < 2) return array[0] || []
|
|
|
+ return [].reduce.call(array, (last, current) => {
|
|
|
+ let res = []
|
|
|
+ last.forEach((l) => {
|
|
|
+ current.forEach((c) => {
|
|
|
+ let temp = [].concat(Array.isArray(l) ? l : [l])
|
|
|
+ temp.push(c)
|
|
|
+ res.push(temp)
|
|
|
+ })
|
|
|
+ })
|
|
|
+ return res
|
|
|
+ })
|
|
|
+ },
|
|
|
+ getTable () {
|
|
|
+ const values = Object.assign({}, this.values)
|
|
|
+ const tableHead = this.patternData
|
|
|
+ .filter(i => i.selected.length)
|
|
|
+ .map(i => i.name)
|
|
|
+ .concat(['售价(元)', '库存', '成本价(元)', '划线价(元)', '操作'])
|
|
|
+
|
|
|
+ const tableBody = this.cartesianProduct(
|
|
|
+ this.patternData.filter(i => i.selected.length).map(i => i.selected)
|
|
|
+ ).map(item => {
|
|
|
+ const id = Array.isArray(item) ? item.join('_') : item
|
|
|
+ values[id] = values[id] || {
|
|
|
+ stock: 0,
|
|
|
+ price: 0,
|
|
|
+ origin_price: 0,
|
|
|
+ cost_price: 0,
|
|
|
+ is_main: 0,
|
|
|
+ invisible: 0,
|
|
|
+ }
|
|
|
+ return {
|
|
|
+ id,
|
|
|
+ stock: 0,
|
|
|
+ price: 0,
|
|
|
+ origin_price: 0,
|
|
|
+ cost_price: 0,
|
|
|
+ is_main: 0,
|
|
|
+ invisible: 0,
|
|
|
+ value: Array.isArray(item) ? item : [item],
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ if (this.value.id) {
|
|
|
+ const exsitIds = []
|
|
|
+ this.value.sku.forEach(({
|
|
|
+ names,
|
|
|
+ price,
|
|
|
+ origin_price: originPrice,
|
|
|
+ cost_price: costPrice,
|
|
|
+ ...others
|
|
|
+ }, index) => {
|
|
|
+ const id = names.map(i => i.value).join('_')
|
|
|
+ exsitIds.push(tableBody.find(t => t.id === id).id)
|
|
|
+ Object.assign(values[id], {
|
|
|
+ invisible: 0,
|
|
|
+ price: price / 100,
|
|
|
+ origin_price: originPrice / 100,
|
|
|
+ cost_price: costPrice / 100,
|
|
|
+ ...others,
|
|
|
+ })
|
|
|
+ })
|
|
|
+ Object.keys(values).forEach(id => {
|
|
|
+ if (this.value.id && !exsitIds.includes(id)) {
|
|
|
+ const index = tableBody.findIndex(i => i.id === id)
|
|
|
+ tableBody.splice(index, 1)
|
|
|
+ delete values[id]
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ if (tableBody.length) {
|
|
|
+ let exist = 0
|
|
|
+ Object.keys(values).find(id => {
|
|
|
+ const isMain = values[id].is_main
|
|
|
+ values[id].is_main = Number(tableBody.find(t => t.id === id) && isMain)
|
|
|
+ exist = values[id].is_main
|
|
|
+ return exist
|
|
|
+ })
|
|
|
+ if (!exist) values[tableBody[0].id].is_main = 1
|
|
|
+ }
|
|
|
+ this.tableData.tableHead = tableHead
|
|
|
+ this.tableData.tableBody = tableBody
|
|
|
+ this.values = values
|
|
|
+ },
|
|
|
+ onMainChange (id) {
|
|
|
+ Object.keys(this.values).forEach(i => {
|
|
|
+ this.values[i].is_main = Number(i === id)
|
|
|
+ })
|
|
|
+ this.onValueChange()
|
|
|
+ },
|
|
|
+ onHidden (id, status) {
|
|
|
+ this.values[id].invisible = Number(!this.values[id].invisible)
|
|
|
+ if (status) {
|
|
|
+ let hasMain = false
|
|
|
+ this.tableData.tableBody.forEach(i => {
|
|
|
+ if (this.values[i.id].is_main && !this.values[i.id].invisible) hasMain = true
|
|
|
+ })
|
|
|
+ if (!hasMain) {
|
|
|
+ const item = this.tableData.tableBody.find(i => {
|
|
|
+ return !this.values[i.id].invisible
|
|
|
+ })
|
|
|
+ if (item) this.onMainChange(item.id)
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ if (this.values[id].is_main) {
|
|
|
+ const item = this.tableData.tableBody.find(i => {
|
|
|
+ return !this.values[i.id].invisible
|
|
|
+ })
|
|
|
+ if (item) this.onMainChange(item.id)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ this.onValueChange()
|
|
|
+ },
|
|
|
+ onValueChange () {
|
|
|
+ const data = Object.keys(this.values).map(id => {
|
|
|
+ const {
|
|
|
+ invisible,
|
|
|
+ price,
|
|
|
+ origin_price: originPrice,
|
|
|
+ cost_price: costPrice,
|
|
|
+ ...other
|
|
|
+ } = this.values[id]
|
|
|
+ const result = !invisible && this.tableData.tableBody.map(i => i.id).includes(id)
|
|
|
+ ? {
|
|
|
+ price: !price ? price : price.toFixed(2) * 100,
|
|
|
+ origin_price: !originPrice ? originPrice : originPrice.toFixed(2) * 100,
|
|
|
+ cost_price: !costPrice ? costPrice : costPrice.toFixed(2) * 100,
|
|
|
+ ...other,
|
|
|
+ }
|
|
|
+ : null
|
|
|
+ if (result && !this.value.id) {
|
|
|
+ result.value = id.split('_')
|
|
|
+ }
|
|
|
+ return result
|
|
|
+ }).filter(Boolean)
|
|
|
+ const item = this.value.patternData.filter(i => i.selected.length).map(i => (
|
|
|
+ {
|
|
|
+ id: i.id,
|
|
|
+ value: i.selected,
|
|
|
+ }
|
|
|
+ ))
|
|
|
+ this.$hub.$emit(this.data.hub, {
|
|
|
+ type: 'value',
|
|
|
+ payload: Object.assign(this.value, {
|
|
|
+ [this.data.keyword]: data,
|
|
|
+ attribute_item: item,
|
|
|
+ }),
|
|
|
+ })
|
|
|
+ },
|
|
|
+ },
|
|
|
+ mounted () {
|
|
|
+ this.getTable()
|
|
|
+ },
|
|
|
+}
|
|
|
+</script>
|
|
|
+<style lang="scss" scoped>
|
|
|
+
|
|
|
+.attr__list {
|
|
|
+ border: 1px solid #ddd;
|
|
|
+ padding: 4px 8px;
|
|
|
+
|
|
|
+ .attr__title {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ padding: 4px 0;
|
|
|
+ background: #eaeaea;
|
|
|
+ .attr__name {
|
|
|
+ width: 100px;
|
|
|
+ font-size: 16px;
|
|
|
+ padding-left: 10px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .attr__input {
|
|
|
+ width: 150px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .attr__item {
|
|
|
+ margin-top: 4px;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.item + .item {
|
|
|
+ margin-top: 4px;
|
|
|
+}
|
|
|
+
|
|
|
+.tag {
|
|
|
+ box-sizing: border-box;
|
|
|
+ position: relative;
|
|
|
+ padding: 2px 4px;
|
|
|
+ border: 1px solid #ccc;
|
|
|
+ border-radius: 2px;
|
|
|
+ font-size: 14px;
|
|
|
+
|
|
|
+ .close {
|
|
|
+ position: absolute;
|
|
|
+ top: -10px;
|
|
|
+ right: -10px;
|
|
|
+ opacity: 0;
|
|
|
+ transition: all .2s;
|
|
|
+ border: 0;
|
|
|
+ background: transparent;
|
|
|
+ outline: none;
|
|
|
+ }
|
|
|
+
|
|
|
+ &:hover .close {
|
|
|
+ opacity: 1;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.attr__table {
|
|
|
+ box-sizing: border-box;
|
|
|
+ width: 100%;
|
|
|
+ font-size: 14px;
|
|
|
+ margin-top: 4px;
|
|
|
+ border: 1px solid #ddd;
|
|
|
+
|
|
|
+ .thead {
|
|
|
+ font-weight: bold;
|
|
|
+ padding: 5px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .tr {
|
|
|
+ box-sizing: inherit;
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+
|
|
|
+ .th, .td {
|
|
|
+ box-sizing: inherit;
|
|
|
+ flex: 1;
|
|
|
+ text-align: center;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .tbody {
|
|
|
+ .tr {
|
|
|
+ padding: 5px;
|
|
|
+ border-top: 1px solid #ccc;
|
|
|
+
|
|
|
+ &:hover {
|
|
|
+ background: #ccc;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.disabled {
|
|
|
+ background: #ddd;
|
|
|
+}
|
|
|
+
|
|
|
+</style>
|