shish 2 kuukautta sitten
vanhempi
commit
4114af2411

+ 549 - 99
ghsPad/src/pages/home/components/discount-panel.vue

@@ -1,416 +1,866 @@
 <template>
+
     <view class="discount-panel" @tap.stop>
+
         <view class="discount-header">
-            <text class="discount-title">选择折扣</text>
+
+            <text class="discount-title">{{ manageMode ? '管理折扣' : '选择折扣' }}</text>
+
             <view class="header-actions">
-                <view class="edit-btn" :class="{ active: editMode }" @tap.stop="toggleEdit">
-                    {{editMode ? '完成' : '新增折扣'}}
-                </view>
-            </view>
-        </view>
 
-        <view v-if="editMode && showAdd" class="add-box">
-            <view class="picker-row">
-                <picker mode="selector" :range="numberOptions" :value="integerIndex" @change="changeInteger">
-                    <view class="picker-value">{{numberOptions[integerIndex]}}</view>
-                </picker>
-                <text class="dot">.</text>
-                <picker mode="selector" :range="numberOptions" :value="decimalIndex" @change="changeDecimal">
-                    <view class="picker-value">{{numberOptions[decimalIndex]}}</view>
-                </picker>
-                <text class="discount-unit">折</text>
+                <view v-if="!manageMode" class="edit-btn" @tap.stop="enterManage">管理</view>
+
+                <view v-else class="edit-btn active" @tap.stop="exitManage">完成</view>
+
             </view>
-            <button class="add-confirm" @tap.stop="addDiscount">添加</button>
+
         </view>
 
+
+
+        <view v-if="manageMode" class="section-label">当前列表 · 排序与删除</view>
+
+
+
         <view class="discount-list">
+
             <view
+
                 v-for="(item, index) in innerList"
+
                 :key="item.value"
+
                 class="discount-item"
+
                 :class="{
-                    active: !editMode && Number(selectedValue) === Number(item.value),
+
+                    active: !manageMode && Number(selectedValue) === Number(item.value),
+
                     dragging: draggingIndex === index,
-                    'add-discount-item': editMode && isNoDiscount(item)
+
+                    'discount-item--last-alone': isLastRowSingleNoDiscount(index)
+
                 }"
+
                 @tap.stop="selectDiscount(item)"
+
             >
-                <text class="discount-name">{{editMode && isNoDiscount(item) ? '+' : item.name}}</text>
-                <view v-if="editMode && !isNoDiscount(item)" class="item-actions">
+
+                <text class="discount-name">{{item.name}}</text>
+
+                <view v-if="manageMode && !isNoDiscount(item)" class="item-actions">
+
                     <view class="delete-btn" @tap.stop="deleteDiscount(index)">×</view>
+
                     <view
+
                         class="drag-handle"
+
                         @tap.stop
+
                         @touchstart.stop="startDrag(index, $event)"
+
                         @touchmove.stop.prevent="moveDrag"
+
                         @touchend.stop="endDrag"
+
                         @touchcancel.stop="endDrag"
+
                     >
+
                         <text></text>
+
                         <text></text>
+
                         <text></text>
+
                     </view>
+
                 </view>
+
             </view>
+
         </view>
-        <view v-if="editMode" class="tips">点击x按钮删除,按住☰按钮拖动排序</view>
+
+
+
+        <view v-if="manageMode" class="manage-hint">「不打折」不可删除,并始终保持在最后。</view>
+
+
+
+        <view v-if="manageMode" class="manage-add-wrap">
+
+            <view class="section-label manage-add-label">添加常用折扣</view>
+
+            <view class="add-box">
+
+                <view class="picker-row">
+
+                    <picker mode="selector" :range="numberOptions" :value="integerIndex" @change="changeInteger">
+
+                        <view class="picker-value">{{numberOptions[integerIndex]}}</view>
+
+                    </picker>
+
+                    <text class="dot">.</text>
+
+                    <picker mode="selector" :range="numberOptions" :value="decimalIndex" @change="changeDecimal">
+
+                        <view class="picker-value">{{numberOptions[decimalIndex]}}</view>
+
+                    </picker>
+
+                    <text class="discount-unit">折</text>
+
+                </view>
+
+                <button class="add-confirm" @tap.stop="addDiscount">添加</button>
+
+            </view>
+
+        </view>
+
     </view>
+
 </template>
 
+
+
 <script>
+
 const DEFAULT_LIST = [
+
     { name: '9折', value: 0.9 },
+
     { name: '不打折', value: 1 },
+
 ]
 
+
+
 export default {
+
     name: 'DiscountPanel',
+
     props: {
+
         value: {
+
             type: Array,
+
             default: () => DEFAULT_LIST
+
         },
+
         selectedValue: {
+
             type: [Number, String],
+
             default: 0
+
         }
+
     },
+
     data() {
+
         return {
+
             innerList: [],
+
             numberOptions: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'],
+
             integerIndex: 8,
+
             decimalIndex: 5,
-            showAdd: false,
-            editMode: false,
+
+            manageMode: false,
+
             draggingIndex: -1,
+
             itemRects: []
+
         }
+
     },
+
     mounted() {
+
         this.initDiscountList()
+
     },
+
     watch: {
+
         value: {
+
             handler(list) {
+
                 if (Array.isArray(this.innerList) && this.innerList.length > 0) return
+
                 this.innerList = this.normalizeList(list)
+
             },
+
             immediate: true,
+
             deep: true
+
         }
+
     },
+
     methods: {
+
         normalizeList(list) {
+
             const source = Array.isArray(list) && list.length > 0 ? list : DEFAULT_LIST
+
             return this.keepNoDiscountLast(source.map(item => ({
+
                 name: item.name,
+
                 value: Number(item.value)
+
             })))
+
         },
+
         keepNoDiscountLast(list) {
+
             const noDiscount = list.find(item => this.isNoDiscount(item)) || { name: '不打折', value: 1 }
+
             return list.filter(item => !this.isNoDiscount(item)).concat([noDiscount])
+
         },
+
         isNoDiscount(item) {
+
             return item && Number(item.value) === 1
+
+        },
+
+        isLastRowSingleNoDiscount(index) {
+
+            const item = this.innerList[index]
+
+            if (!this.isNoDiscount(item)) return false
+
+            const len = this.innerList.length
+
+            return len > 0 && index === len - 1 && len % 3 === 1
+
         },
+
         initDiscountList() {
+
             let cacheList = []
+
             if (this.$store && this.$store.getters) {
+
                 cacheList = this.$store.getters.getDiscountList
+
             }
+
             const nextList = this.normalizeList(Array.isArray(cacheList) && cacheList.length > 0 ? cacheList : DEFAULT_LIST)
+
             this.innerList = nextList
+
             this.$emit('input', nextList.slice())
+
             this.$emit('change-list', nextList.slice())
+
         },
+
         emitList() {
+
             this.innerList = this.keepNoDiscountLast(this.innerList)
+
             if (this.$store && this.$store.dispatch) {
+
                 this.$store.dispatch('setDiscountListCache', this.innerList.slice())
+
             }
+
             this.$emit('input', this.innerList.slice())
+
             this.$emit('change-list', this.innerList.slice())
+
         },
-        toggleEdit() {
-            this.editMode = !this.editMode
-            if (!this.editMode) {
-                this.showAdd = false
-                this.endDrag()
-            }
+
+        enterManage() {
+
+            this.manageMode = true
+
         },
+
+        exitManage() {
+
+            this.manageMode = false
+
+            this.endDrag()
+
+        },
+
         changeInteger(e) {
+
             this.integerIndex = Number(e.detail.value)
+
         },
+
         changeDecimal(e) {
+
             this.decimalIndex = Number(e.detail.value)
+
         },
+
         addDiscount() {
+
             const integer = Number(this.numberOptions[this.integerIndex])
+
             const decimal = Number(this.numberOptions[this.decimalIndex])
+
             const value = Number(((integer * 10 + decimal) / 100).toFixed(2))
+
             if (value <= 0) {
+
                 uni.showToast({ title: '折扣不能为0', icon: 'none' })
+
                 return
+
             }
+
             if (this.innerList.some(item => Number(item.value) === value)) {
+
                 uni.showToast({ title: '该折扣已存在', icon: 'none' })
+
                 return
+
             }
+
             const name = decimal === 0 ? `${integer}折` : `${integer}.${decimal}折`
+
             const noDiscountIndex = this.innerList.findIndex(item => this.isNoDiscount(item))
+
             if (noDiscountIndex === -1) {
+
                 this.innerList.push({ name, value }, { name: '不打折', value: 1 })
+
             } else {
+
                 this.innerList.splice(noDiscountIndex, 0, { name, value })
+
             }
-            this.showAdd = false
+
             this.emitList()
+
         },
+
         deleteDiscount(index) {
+
             if (this.isNoDiscount(this.innerList[index])) {
+
                 return
+
             }
+
             if (this.innerList.length <= 1) {
+
                 uni.showToast({ title: '至少保留一个折扣', icon: 'none' })
+
                 return
+
             }
+
             uni.showModal({
+
                 title: '删除折扣',
+
                 content: `确定删除${this.innerList[index].name}吗?`,
+
                 success: (res) => {
+
                     if (!res.confirm) return
+
                     const deleted = this.innerList.splice(index, 1)[0]
+
                     this.emitList()
+
                     if (deleted && Number(deleted.value) === Number(this.selectedValue)) {
+
                         this.$emit('select', this.innerList[0].value)
+
                     }
+
                 }
+
             })
+
         },
+
         selectDiscount(item) {
+
             if (this.draggingIndex !== -1) return
-            if (this.editMode && this.isNoDiscount(item)) {
-                this.showAdd = !this.showAdd
-                return
-            }
+
+            if (this.manageMode) return
+
             this.$emit('select', item.value)
+
         },
+
         startDrag(index) {
-            if (!this.editMode || this.isNoDiscount(this.innerList[index])) return
+
+            if (!this.manageMode || this.isNoDiscount(this.innerList[index])) return
+
             this.draggingIndex = index
+
             this.queryItemRects()
+
         },
+
         moveDrag(e) {
+
             if (this.draggingIndex === -1) return
+
             const touch = e.touches && e.touches[0]
+
             if (!touch || this.itemRects.length === 0) return
+
             const targetIndex = this.itemRects.findIndex(rect => (
+
                 touch.clientX >= rect.left &&
+
                 touch.clientX <= rect.right &&
+
                 touch.clientY >= rect.top &&
+
                 touch.clientY <= rect.bottom
+
             ))
+
             if (
+
                 targetIndex === -1 ||
+
                 targetIndex === this.draggingIndex ||
+
                 this.isNoDiscount(this.innerList[targetIndex])
+
             ) return
+
             const current = this.innerList.splice(this.draggingIndex, 1)[0]
+
             this.innerList.splice(targetIndex, 0, current)
+
             this.innerList = this.keepNoDiscountLast(this.innerList)
+
             this.draggingIndex = targetIndex
+
             this.$nextTick(() => {
+
                 this.queryItemRects()
+
             })
+
         },
+
         endDrag() {
+
             if (this.draggingIndex !== -1) {
+
                 this.emitList()
+
             }
+
             this.draggingIndex = -1
+
             this.itemRects = []
+
         },
+
         queryItemRects() {
+
             this.$nextTick(() => {
+
                 uni.createSelectorQuery()
+
                     .in(this)
+
                     .selectAll('.discount-item')
+
                     .boundingClientRect((rects) => {
+
                         this.itemRects = Array.isArray(rects) ? rects : []
+
                     })
+
                     .exec()
+
             })
+
         }
+
     }
+
 }
+
 </script>
 
+
+
 <style lang="scss" scoped>
+
 .discount-panel {
+
     position: absolute;
+
     top: 0;
+
     left: 50%;
+
     transform: translateX(-50%);
-    width: 190upx;
-    padding: 12upx;
+
+    width: 337upx;
+
+    padding: 16upx;
+
     background-color: #ffffff;
+
     border: 1upx solid #eeeeee;
-    border-radius: 6upx;
+
+    border-radius: 8upx;
+
     z-index: 99999999;
-    box-shadow: 0 4upx 16upx rgba(0, 0, 0, 0.12);
+
+    box-shadow: 0 5upx 21upx rgba(0, 0, 0, 0.12);
+
 }
+
 .discount-header {
+
     display: flex;
+
     align-items: center;
+
     justify-content: space-between;
-    margin-bottom: 10upx;
+
+    margin-bottom: 13upx;
+
 }
+
 .discount-title {
-    font-size: 12upx;
+
+    font-size: 16upx;
+
     color: #333333;
+
     font-weight: bold;
+
 }
+
+.section-label {
+
+    font-size: 12upx;
+
+    color: #999999;
+
+    margin-bottom: 8upx;
+
+    line-height: 1.3;
+
+}
+
+.manage-add-label {
+
+    margin-top: 13upx;
+
+    margin-bottom: 6upx;
+
+}
+
+.manage-hint {
+
+    margin-top: 6upx;
+
+    font-size: 11upx;
+
+    color: #bbbbbb;
+
+    line-height: 1.4;
+
+}
+
+.manage-add-wrap {
+
+    margin-top: 0;
+
+}
+
 .header-actions {
+
     display: flex;
+
     align-items: center;
+
+}
+
+.header-actions .edit-btn + .edit-btn {
+
+    margin-left: 11upx;
+
 }
+
 .edit-btn {
-    min-width: 34upx;
-    height: 24upx;
-    line-height: 24upx;
-    margin-left: 8upx;
-    padding: 0 6upx;
+
+    min-width: 45upx;
+
+    height: 32upx;
+
+    line-height: 32upx;
+
+    padding: 0 8upx;
+
     text-align: center;
-    border-radius: 12upx;
+
+    border-radius: 16upx;
+
     border: 1upx solid #09C567;
+
     color: #09C567;
-    font-size: 10upx;
+
+    font-size: 13upx;
+
 }
+
 .edit-btn.active {
+
     color: #ffffff;
+
     background-color: #09C567;
+
 }
+
 .add-box {
-    padding: 8upx;
-    margin-bottom: 10upx;
+
+    padding: 11upx;
+
     background-color: #f8f8f8;
-    border-radius: 4upx;
+
+    border-radius: 5upx;
+
 }
+
 .picker-row {
+
     display: flex;
+
     align-items: center;
+
     justify-content: center;
+
 }
+
 .picker-value {
-    width: 36upx;
-    height: 28upx;
-    line-height: 28upx;
+
+    width: 48upx;
+
+    height: 37upx;
+
+    line-height: 37upx;
+
     text-align: center;
+
     border: 1upx solid #dddddd;
-    border-radius: 4upx;
+
+    border-radius: 5upx;
+
     background-color: #ffffff;
-    font-size: 12upx;
+
+    font-size: 16upx;
+
 }
+
 .dot,
+
 .discount-unit {
-    font-size: 12upx;
+
+    font-size: 16upx;
+
     color: #333333;
-    margin-left: 4upx;
+
+    margin-left: 5upx;
+
 }
+
 .add-confirm {
-    height: 28upx;
-    line-height: 28upx;
-    margin-top: 8upx;
+
+    width: 100%;
+
+    height: 37upx;
+
+    line-height: 37upx;
+
+    margin-top: 11upx;
+
+    margin-left: 0;
+
     padding: 0;
-    font-size: 12upx;
+
+    font-size: 16upx;
+
     color: #ffffff;
+
     background-color: #09C567;
-    border-radius: 4upx;
+
+    border-radius: 5upx;
+
 }
+
 .discount-list {
-    display: flex;
+
+    display: grid;
+
+    grid-template-columns: repeat(3, 1fr);
+
+    justify-items: center;
+
     align-items: center;
-    flex-wrap: wrap;
+
+    width: 100%;
+
+    box-sizing: border-box;
+
 }
+
 .discount-item {
-    width: 48upx;
-    height: 48upx;
-    margin-left: 8upx;
-    margin-bottom: 8upx;
+
+    width: 64upx;
+
+    height: 64upx;
+
+    margin-left: 0;
+
+    margin-bottom: 11upx;
+
     border: 1upx solid #999999;
-    border-radius: 24upx;
+
+    border-radius: 32upx;
+
     display: flex;
+
     align-items: center;
+
     justify-content: center;
+
     position: relative;
+
     background-color: #ffffff;
+
 }
-.discount-item:nth-child(3n + 1) {
-    margin-left: 0;
+
+.discount-item--last-alone {
+
+    grid-column: 2;
+
 }
+
 .discount-item.active {
+
     border-color: #09C567;
+
     color: #09C567;
+
 }
+
 .discount-item.dragging {
+
     opacity: 0.7;
+
     background-color: #f0fff8;
+
 }
-.discount-item.add-discount-item {
-    border-color: #09C567;
-    color: #09C567;
-    font-size: 18upx;
-}
+
 .discount-name {
-    font-size: 10upx;
-}
-.add-discount-item .discount-name {
-    font-size: 20upx;
-    line-height: 20upx;
+
+    font-size: 13upx;
+
 }
+
 .item-actions {
+
     position: absolute;
-    top: -4upx;
-    right: -12upx;
+
+    top: -5upx;
+
+    right: -16upx;
+
     display: flex;
+
     align-items: center;
+
 }
+
 .delete-btn,
+
 .drag-handle {
-    width: 18upx;
-    height: 18upx;
-    border-radius: 9upx;
+
+    width: 24upx;
+
+    height: 24upx;
+
+    border-radius: 12upx;
+
 }
+
 .delete-btn {
-    line-height: 16upx;
+
+    line-height: 21upx;
+
     text-align: center;
-    margin-right: 10upx;
+
+    margin-right: 13upx;
+
     background-color: #ff4d4f;
+
     color: #ffffff;
-    font-size: 14upx;
+
+    font-size: 19upx;
+
 }
+
 .drag-handle {
+
     background-color: #666666;
+
     display: flex;
+
     flex-direction: column;
+
     align-items: center;
+
     justify-content: center;
-    margin-right: 12upx;
+
+    margin-right: 16upx;
+
 }
+
 .drag-handle text {
-    width: 8upx;
+
+    width: 11upx;
+
     height: 1upx;
-    margin-top: 2upx;
+
+    margin-top: 3upx;
+
     background-color: #ffffff;
+
 }
+
 .drag-handle text:first-child {
+
     margin-top: 0;
+
 }
-.tips {
-    margin-top: 2upx;
-    font-size: 9upx;
-    color: #999999;
-}
+
 </style>
+

+ 549 - 99
hdPad/src/pages/home/components/discount-panel.vue

@@ -1,416 +1,866 @@
 <template>
+
     <view class="discount-panel" @tap.stop>
+
         <view class="discount-header">
-            <text class="discount-title">选择折扣</text>
+
+            <text class="discount-title">{{ manageMode ? '管理折扣' : '选择折扣' }}</text>
+
             <view class="header-actions">
-                <view class="edit-btn" :class="{ active: editMode }" @tap.stop="toggleEdit">
-                    {{editMode ? '完成' : '新增折扣'}}
-                </view>
-            </view>
-        </view>
 
-        <view v-if="editMode && showAdd" class="add-box">
-            <view class="picker-row">
-                <picker mode="selector" :range="numberOptions" :value="integerIndex" @change="changeInteger">
-                    <view class="picker-value">{{numberOptions[integerIndex]}}</view>
-                </picker>
-                <text class="dot">.</text>
-                <picker mode="selector" :range="numberOptions" :value="decimalIndex" @change="changeDecimal">
-                    <view class="picker-value">{{numberOptions[decimalIndex]}}</view>
-                </picker>
-                <text class="discount-unit">折</text>
+                <view v-if="!manageMode" class="edit-btn" @tap.stop="enterManage">管理</view>
+
+                <view v-else class="edit-btn active" @tap.stop="exitManage">完成</view>
+
             </view>
-            <button class="add-confirm" @tap.stop="addDiscount">添加</button>
+
         </view>
 
+
+
+        <view v-if="manageMode" class="section-label">当前列表 · 排序与删除</view>
+
+
+
         <view class="discount-list">
+
             <view
+
                 v-for="(item, index) in innerList"
+
                 :key="item.value"
+
                 class="discount-item"
+
                 :class="{
-                    active: !editMode && Number(selectedValue) === Number(item.value),
+
+                    active: !manageMode && Number(selectedValue) === Number(item.value),
+
                     dragging: draggingIndex === index,
-                    'add-discount-item': editMode && isNoDiscount(item)
+
+                    'discount-item--last-alone': isLastRowSingleNoDiscount(index)
+
                 }"
+
                 @tap.stop="selectDiscount(item)"
+
             >
-                <text class="discount-name">{{editMode && isNoDiscount(item) ? '+' : item.name}}</text>
-                <view v-if="editMode && !isNoDiscount(item)" class="item-actions">
+
+                <text class="discount-name">{{item.name}}</text>
+
+                <view v-if="manageMode && !isNoDiscount(item)" class="item-actions">
+
                     <view class="delete-btn" @tap.stop="deleteDiscount(index)">×</view>
+
                     <view
+
                         class="drag-handle"
+
                         @tap.stop
+
                         @touchstart.stop="startDrag(index, $event)"
+
                         @touchmove.stop.prevent="moveDrag"
+
                         @touchend.stop="endDrag"
+
                         @touchcancel.stop="endDrag"
+
                     >
+
                         <text></text>
+
                         <text></text>
+
                         <text></text>
+
                     </view>
+
                 </view>
+
             </view>
+
         </view>
-        <view v-if="editMode" class="tips">点击x按钮删除,按住☰按钮拖动排序</view>
+
+
+
+        <view v-if="manageMode" class="manage-hint">「不打折」不可删除,并始终保持在最后。</view>
+
+
+
+        <view v-if="manageMode" class="manage-add-wrap">
+
+            <view class="section-label manage-add-label">添加常用折扣</view>
+
+            <view class="add-box">
+
+                <view class="picker-row">
+
+                    <picker mode="selector" :range="numberOptions" :value="integerIndex" @change="changeInteger">
+
+                        <view class="picker-value">{{numberOptions[integerIndex]}}</view>
+
+                    </picker>
+
+                    <text class="dot">.</text>
+
+                    <picker mode="selector" :range="numberOptions" :value="decimalIndex" @change="changeDecimal">
+
+                        <view class="picker-value">{{numberOptions[decimalIndex]}}</view>
+
+                    </picker>
+
+                    <text class="discount-unit">折</text>
+
+                </view>
+
+                <button class="add-confirm" @tap.stop="addDiscount">添加</button>
+
+            </view>
+
+        </view>
+
     </view>
+
 </template>
 
+
+
 <script>
+
 const DEFAULT_LIST = [
+
     { name: '9折', value: 0.9 },
+
     { name: '不打折', value: 1 },
+
 ]
 
+
+
 export default {
+
     name: 'DiscountPanel',
+
     props: {
+
         value: {
+
             type: Array,
+
             default: () => DEFAULT_LIST
+
         },
+
         selectedValue: {
+
             type: [Number, String],
+
             default: 0
+
         }
+
     },
+
     data() {
+
         return {
+
             innerList: [],
+
             numberOptions: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'],
+
             integerIndex: 8,
+
             decimalIndex: 5,
-            showAdd: false,
-            editMode: false,
+
+            manageMode: false,
+
             draggingIndex: -1,
+
             itemRects: []
+
         }
+
     },
+
     mounted() {
+
         this.initDiscountList()
+
     },
+
     watch: {
+
         value: {
+
             handler(list) {
+
                 if (Array.isArray(this.innerList) && this.innerList.length > 0) return
+
                 this.innerList = this.normalizeList(list)
+
             },
+
             immediate: true,
+
             deep: true
+
         }
+
     },
+
     methods: {
+
         normalizeList(list) {
+
             const source = Array.isArray(list) && list.length > 0 ? list : DEFAULT_LIST
+
             return this.keepNoDiscountLast(source.map(item => ({
+
                 name: item.name,
+
                 value: Number(item.value)
+
             })))
+
         },
+
         keepNoDiscountLast(list) {
+
             const noDiscount = list.find(item => this.isNoDiscount(item)) || { name: '不打折', value: 1 }
+
             return list.filter(item => !this.isNoDiscount(item)).concat([noDiscount])
+
         },
+
         isNoDiscount(item) {
+
             return item && Number(item.value) === 1
+
+        },
+
+        isLastRowSingleNoDiscount(index) {
+
+            const item = this.innerList[index]
+
+            if (!this.isNoDiscount(item)) return false
+
+            const len = this.innerList.length
+
+            return len > 0 && index === len - 1 && len % 3 === 1
+
         },
+
         initDiscountList() {
+
             let cacheList = []
+
             if (this.$store && this.$store.getters) {
+
                 cacheList = this.$store.getters.getDiscountList
+
             }
+
             const nextList = this.normalizeList(Array.isArray(cacheList) && cacheList.length > 0 ? cacheList : DEFAULT_LIST)
+
             this.innerList = nextList
+
             this.$emit('input', nextList.slice())
+
             this.$emit('change-list', nextList.slice())
+
         },
+
         emitList() {
+
             this.innerList = this.keepNoDiscountLast(this.innerList)
+
             if (this.$store && this.$store.dispatch) {
+
                 this.$store.dispatch('setDiscountListCache', this.innerList.slice())
+
             }
+
             this.$emit('input', this.innerList.slice())
+
             this.$emit('change-list', this.innerList.slice())
+
         },
-        toggleEdit() {
-            this.editMode = !this.editMode
-            if (!this.editMode) {
-                this.showAdd = false
-                this.endDrag()
-            }
+
+        enterManage() {
+
+            this.manageMode = true
+
         },
+
+        exitManage() {
+
+            this.manageMode = false
+
+            this.endDrag()
+
+        },
+
         changeInteger(e) {
+
             this.integerIndex = Number(e.detail.value)
+
         },
+
         changeDecimal(e) {
+
             this.decimalIndex = Number(e.detail.value)
+
         },
+
         addDiscount() {
+
             const integer = Number(this.numberOptions[this.integerIndex])
+
             const decimal = Number(this.numberOptions[this.decimalIndex])
+
             const value = Number(((integer * 10 + decimal) / 100).toFixed(2))
+
             if (value <= 0) {
+
                 uni.showToast({ title: '折扣不能为0', icon: 'none' })
+
                 return
+
             }
+
             if (this.innerList.some(item => Number(item.value) === value)) {
+
                 uni.showToast({ title: '该折扣已存在', icon: 'none' })
+
                 return
+
             }
+
             const name = decimal === 0 ? `${integer}折` : `${integer}.${decimal}折`
+
             const noDiscountIndex = this.innerList.findIndex(item => this.isNoDiscount(item))
+
             if (noDiscountIndex === -1) {
+
                 this.innerList.push({ name, value }, { name: '不打折', value: 1 })
+
             } else {
+
                 this.innerList.splice(noDiscountIndex, 0, { name, value })
+
             }
-            this.showAdd = false
+
             this.emitList()
+
         },
+
         deleteDiscount(index) {
+
             if (this.isNoDiscount(this.innerList[index])) {
+
                 return
+
             }
+
             if (this.innerList.length <= 1) {
+
                 uni.showToast({ title: '至少保留一个折扣', icon: 'none' })
+
                 return
+
             }
+
             uni.showModal({
+
                 title: '删除折扣',
+
                 content: `确定删除${this.innerList[index].name}吗?`,
+
                 success: (res) => {
+
                     if (!res.confirm) return
+
                     const deleted = this.innerList.splice(index, 1)[0]
+
                     this.emitList()
+
                     if (deleted && Number(deleted.value) === Number(this.selectedValue)) {
+
                         this.$emit('select', this.innerList[0].value)
+
                     }
+
                 }
+
             })
+
         },
+
         selectDiscount(item) {
+
             if (this.draggingIndex !== -1) return
-            if (this.editMode && this.isNoDiscount(item)) {
-                this.showAdd = !this.showAdd
-                return
-            }
+
+            if (this.manageMode) return
+
             this.$emit('select', item.value)
+
         },
+
         startDrag(index) {
-            if (!this.editMode || this.isNoDiscount(this.innerList[index])) return
+
+            if (!this.manageMode || this.isNoDiscount(this.innerList[index])) return
+
             this.draggingIndex = index
+
             this.queryItemRects()
+
         },
+
         moveDrag(e) {
+
             if (this.draggingIndex === -1) return
+
             const touch = e.touches && e.touches[0]
+
             if (!touch || this.itemRects.length === 0) return
+
             const targetIndex = this.itemRects.findIndex(rect => (
+
                 touch.clientX >= rect.left &&
+
                 touch.clientX <= rect.right &&
+
                 touch.clientY >= rect.top &&
+
                 touch.clientY <= rect.bottom
+
             ))
+
             if (
+
                 targetIndex === -1 ||
+
                 targetIndex === this.draggingIndex ||
+
                 this.isNoDiscount(this.innerList[targetIndex])
+
             ) return
+
             const current = this.innerList.splice(this.draggingIndex, 1)[0]
+
             this.innerList.splice(targetIndex, 0, current)
+
             this.innerList = this.keepNoDiscountLast(this.innerList)
+
             this.draggingIndex = targetIndex
+
             this.$nextTick(() => {
+
                 this.queryItemRects()
+
             })
+
         },
+
         endDrag() {
+
             if (this.draggingIndex !== -1) {
+
                 this.emitList()
+
             }
+
             this.draggingIndex = -1
+
             this.itemRects = []
+
         },
+
         queryItemRects() {
+
             this.$nextTick(() => {
+
                 uni.createSelectorQuery()
+
                     .in(this)
+
                     .selectAll('.discount-item')
+
                     .boundingClientRect((rects) => {
+
                         this.itemRects = Array.isArray(rects) ? rects : []
+
                     })
+
                     .exec()
+
             })
+
         }
+
     }
+
 }
+
 </script>
 
+
+
 <style lang="scss" scoped>
+
 .discount-panel {
+
     position: absolute;
+
     top: 0;
+
     left: 50%;
+
     transform: translateX(-50%);
-    width: 190upx;
-    padding: 12upx;
+
+    width: 337upx;
+
+    padding: 16upx;
+
     background-color: #ffffff;
+
     border: 1upx solid #eeeeee;
-    border-radius: 6upx;
+
+    border-radius: 8upx;
+
     z-index: 99999999;
-    box-shadow: 0 4upx 16upx rgba(0, 0, 0, 0.12);
+
+    box-shadow: 0 5upx 21upx rgba(0, 0, 0, 0.12);
+
 }
+
 .discount-header {
+
     display: flex;
+
     align-items: center;
+
     justify-content: space-between;
-    margin-bottom: 10upx;
+
+    margin-bottom: 13upx;
+
 }
+
 .discount-title {
-    font-size: 12upx;
+
+    font-size: 16upx;
+
     color: #333333;
+
     font-weight: bold;
+
 }
+
+.section-label {
+
+    font-size: 12upx;
+
+    color: #999999;
+
+    margin-bottom: 8upx;
+
+    line-height: 1.3;
+
+}
+
+.manage-add-label {
+
+    margin-top: 13upx;
+
+    margin-bottom: 6upx;
+
+}
+
+.manage-hint {
+
+    margin-top: 6upx;
+
+    font-size: 11upx;
+
+    color: #bbbbbb;
+
+    line-height: 1.4;
+
+}
+
+.manage-add-wrap {
+
+    margin-top: 0;
+
+}
+
 .header-actions {
+
     display: flex;
+
     align-items: center;
+
+}
+
+.header-actions .edit-btn + .edit-btn {
+
+    margin-left: 11upx;
+
 }
+
 .edit-btn {
-    min-width: 34upx;
-    height: 24upx;
-    line-height: 24upx;
-    margin-left: 8upx;
-    padding: 0 6upx;
+
+    min-width: 45upx;
+
+    height: 32upx;
+
+    line-height: 32upx;
+
+    padding: 0 8upx;
+
     text-align: center;
-    border-radius: 12upx;
+
+    border-radius: 16upx;
+
     border: 1upx solid #09C567;
+
     color: #09C567;
-    font-size: 10upx;
+
+    font-size: 13upx;
+
 }
+
 .edit-btn.active {
+
     color: #ffffff;
+
     background-color: #09C567;
+
 }
+
 .add-box {
-    padding: 8upx;
-    margin-bottom: 10upx;
+
+    padding: 11upx;
+
     background-color: #f8f8f8;
-    border-radius: 4upx;
+
+    border-radius: 5upx;
+
 }
+
 .picker-row {
+
     display: flex;
+
     align-items: center;
+
     justify-content: center;
+
 }
+
 .picker-value {
-    width: 36upx;
-    height: 28upx;
-    line-height: 28upx;
+
+    width: 48upx;
+
+    height: 37upx;
+
+    line-height: 37upx;
+
     text-align: center;
+
     border: 1upx solid #dddddd;
-    border-radius: 4upx;
+
+    border-radius: 5upx;
+
     background-color: #ffffff;
-    font-size: 12upx;
+
+    font-size: 16upx;
+
 }
+
 .dot,
+
 .discount-unit {
-    font-size: 12upx;
+
+    font-size: 16upx;
+
     color: #333333;
-    margin-left: 4upx;
+
+    margin-left: 5upx;
+
 }
+
 .add-confirm {
-    height: 28upx;
-    line-height: 28upx;
-    margin-top: 8upx;
+
+    width: 100%;
+
+    height: 37upx;
+
+    line-height: 37upx;
+
+    margin-top: 11upx;
+
+    margin-left: 0;
+
     padding: 0;
-    font-size: 12upx;
+
+    font-size: 16upx;
+
     color: #ffffff;
+
     background-color: #09C567;
-    border-radius: 4upx;
+
+    border-radius: 5upx;
+
 }
+
 .discount-list {
-    display: flex;
+
+    display: grid;
+
+    grid-template-columns: repeat(3, 1fr);
+
+    justify-items: center;
+
     align-items: center;
-    flex-wrap: wrap;
+
+    width: 100%;
+
+    box-sizing: border-box;
+
 }
+
 .discount-item {
-    width: 48upx;
-    height: 48upx;
-    margin-left: 8upx;
-    margin-bottom: 8upx;
+
+    width: 64upx;
+
+    height: 64upx;
+
+    margin-left: 0;
+
+    margin-bottom: 11upx;
+
     border: 1upx solid #999999;
-    border-radius: 24upx;
+
+    border-radius: 32upx;
+
     display: flex;
+
     align-items: center;
+
     justify-content: center;
+
     position: relative;
+
     background-color: #ffffff;
+
 }
-.discount-item:nth-child(3n + 1) {
-    margin-left: 0;
+
+.discount-item--last-alone {
+
+    grid-column: 2;
+
 }
+
 .discount-item.active {
+
     border-color: #09C567;
+
     color: #09C567;
+
 }
+
 .discount-item.dragging {
+
     opacity: 0.7;
+
     background-color: #f0fff8;
+
 }
-.discount-item.add-discount-item {
-    border-color: #09C567;
-    color: #09C567;
-    font-size: 18upx;
-}
+
 .discount-name {
-    font-size: 10upx;
-}
-.add-discount-item .discount-name {
-    font-size: 20upx;
-    line-height: 20upx;
+
+    font-size: 13upx;
+
 }
+
 .item-actions {
+
     position: absolute;
-    top: -4upx;
-    right: -12upx;
+
+    top: -5upx;
+
+    right: -16upx;
+
     display: flex;
+
     align-items: center;
+
 }
+
 .delete-btn,
+
 .drag-handle {
-    width: 18upx;
-    height: 18upx;
-    border-radius: 9upx;
+
+    width: 24upx;
+
+    height: 24upx;
+
+    border-radius: 12upx;
+
 }
+
 .delete-btn {
-    line-height: 16upx;
+
+    line-height: 21upx;
+
     text-align: center;
-    margin-right: 10upx;
+
+    margin-right: 13upx;
+
     background-color: #ff4d4f;
+
     color: #ffffff;
-    font-size: 14upx;
+
+    font-size: 19upx;
+
 }
+
 .drag-handle {
+
     background-color: #666666;
+
     display: flex;
+
     flex-direction: column;
+
     align-items: center;
+
     justify-content: center;
-    margin-right: 12upx;
+
+    margin-right: 16upx;
+
 }
+
 .drag-handle text {
-    width: 8upx;
+
+    width: 11upx;
+
     height: 1upx;
-    margin-top: 2upx;
+
+    margin-top: 3upx;
+
     background-color: #ffffff;
+
 }
+
 .drag-handle text:first-child {
+
     margin-top: 0;
+
 }
-.tips {
-    margin-top: 2upx;
-    font-size: 9upx;
-    color: #999999;
-}
+
 </style>
+