ソースを参照

feat:假货模块 + u-cell二次封装 + u-table二次封装

zhangxin 1 ヶ月 前
コミット
9207857e5f
共有33 個のファイルを変更した2958 個の追加88 個の削除を含む
  1. 15 0
      components/custom-cell/index.scss
  2. 56 0
      components/custom-cell/index.vue
  3. 133 0
      components/custom-table/index.scss
  4. 163 0
      components/custom-table/index.vue
  5. 0 17
      components/form-select-to-page/index.scss
  6. 0 53
      components/form-select-to-page/index.vue
  7. 6 0
      main.js
  8. 213 2
      mock/mockData.js
  9. 8 0
      pages.json
  10. 12 9
      pages/wareHouse/components/add.vue
  11. 181 0
      pages/wareHouse/components/fakeRegistration.vue
  12. 6 6
      pages/wareHouse/components/searchFilter.vue
  13. 6 1
      pages/wareHouse/index.vue
  14. 28 0
      pages/wareHouse/styles/fakeRegistration.scss
  15. 35 0
      uni_modules/uni-table/changelog.md
  16. 460 0
      uni_modules/uni-table/components/uni-table/uni-table.vue
  17. 34 0
      uni_modules/uni-table/components/uni-tbody/uni-tbody.vue
  18. 95 0
      uni_modules/uni-table/components/uni-td/uni-td.vue
  19. 511 0
      uni_modules/uni-table/components/uni-th/filter-dropdown.vue
  20. 295 0
      uni_modules/uni-table/components/uni-th/uni-th.vue
  21. 137 0
      uni_modules/uni-table/components/uni-thead/uni-thead.vue
  22. 179 0
      uni_modules/uni-table/components/uni-tr/table-checkbox.vue
  23. 184 0
      uni_modules/uni-table/components/uni-tr/uni-tr.vue
  24. 9 0
      uni_modules/uni-table/i18n/en.json
  25. 9 0
      uni_modules/uni-table/i18n/es.json
  26. 9 0
      uni_modules/uni-table/i18n/fr.json
  27. 12 0
      uni_modules/uni-table/i18n/index.js
  28. 9 0
      uni_modules/uni-table/i18n/zh-Hans.json
  29. 9 0
      uni_modules/uni-table/i18n/zh-Hant.json
  30. 86 0
      uni_modules/uni-table/package.json
  31. 13 0
      uni_modules/uni-table/readme.md
  32. 3 0
      utils/api.js
  33. 42 0
      utils/doubleTap.js

+ 15 - 0
components/custom-cell/index.scss

@@ -0,0 +1,15 @@
1
+.u-cell{
2
+    width: 100%;
3
+    .cell_wrap{
4
+        display: flex;
5
+        align-items: center;
6
+        gap: 10rpx;
7
+        font-size:26rpx;
8
+        .dict_label{
9
+            color: #303133;
10
+        }
11
+        .placeholder{
12
+            color: #606266;
13
+        }
14
+    }
15
+}

+ 56 - 0
components/custom-cell/index.vue

@@ -0,0 +1,56 @@
1
+<template>
2
+    <u-cell :isLink="isLink" :arrow-direction="arrowDirection" :border="border" :center="center">
3
+        <view slot="value" class="cell_wrap">
4
+            <view v-if="val" class="dictLabel">{{ val }}</view>
5
+            <view v-else class="placeholder">请选择</view>
6
+            <view v-if="isDelete && val" @click.stop="clear()">
7
+                <u-icon size="15" name="close-circle"></u-icon>
8
+            </view>
9
+        </view>
10
+    </u-cell>
11
+</template>
12
+
13
+<script>
14
+export default {
15
+  name: 'CustomCell',
16
+  data() {
17
+    return {}
18
+  },
19
+  props: {
20
+    isLink: {
21
+      type: Boolean,
22
+      default: true,
23
+    },
24
+    arrowDirection: {
25
+      type: String,
26
+      default: 'right',
27
+    },
28
+    border: {
29
+      type: Boolean,
30
+      default: false,
31
+    },
32
+    center: {
33
+      type: Boolean,
34
+      default: true,
35
+    },
36
+    val: {
37
+      type: String,
38
+      default: '',
39
+    },
40
+    isDelete: {
41
+        type: Boolean,
42
+        default: false,
43
+    },
44
+
45
+  },
46
+  emits: ['handleClear'],
47
+  methods: {
48
+    clear(){
49
+      this.$emit('handleClear');
50
+    }
51
+  }
52
+}
53
+</script>
54
+<style scoped>
55
+@import './index.scss';
56
+</style>

+ 133 - 0
components/custom-table/index.scss

@@ -0,0 +1,133 @@
1
+::v-deep .custom-table {
2
+  // width: 100%;
3
+  // height: calc(100vh - 380rpx);
4
+  
5
+  &__require {
6
+    color: #ff4949;
7
+    margin-right: 4rpx;
8
+  }
9
+  
10
+  &__load-more {
11
+    display: flex;
12
+    justify-content: center;
13
+    align-items: center;
14
+    padding: 30rpx 0;
15
+    color: #909399;
16
+    font-size: 24rpx;
17
+    border-top: 1rpx solid #e4e7ed;
18
+  }
19
+  
20
+  &__load-more-text {
21
+    margin: 0 10rpx;
22
+  }
23
+
24
+  &__body {
25
+    // height: calc(100vh - 380rpx);
26
+    overflow: auto;
27
+  }
28
+}
29
+
30
+::v-deep .uni-scroll-view{
31
+  height: calc(100vh - 260rpx);
32
+}
33
+
34
+::v-deep .uni-table {
35
+  width: 100%;
36
+  border-radius: 8rpx;
37
+  overflow: hidden;
38
+  border: 1rpx solid #e4e7ed;
39
+  
40
+  .uni-table__body {
41
+    overflow: auto;
42
+  }
43
+  
44
+  .uni-th {
45
+    background-color: #f5f7fa;
46
+    font-weight: 600;
47
+    font-size: 26rpx;
48
+    color: #303133;
49
+    padding: 30rpx 20rpx;
50
+    text-align: center;
51
+    border-right: 1rpx solid #e4e7ed;
52
+    border-bottom: 1rpx solid #e4e7ed;
53
+    position: sticky;
54
+    top: 0;
55
+    z-index: 10;
56
+    box-shadow: 0 2rpx 4rpx rgba(0, 0, 0, 0.05);
57
+  }
58
+  
59
+  .uni-td {
60
+    padding: 0 20rpx;
61
+    font-size: 24rpx;
62
+    color: #606266;
63
+    text-align: center;
64
+    border-right: 1rpx solid #e4e7ed;
65
+    border-bottom: 1rpx solid #e4e7ed;
66
+    height: 120rpx;
67
+    display: flex;
68
+    align-items: center;
69
+    justify-content: center;
70
+    
71
+    > * {
72
+      display: -webkit-box;
73
+      -webkit-line-clamp: 2;
74
+      -webkit-box-orient: vertical;
75
+      overflow: hidden;
76
+      text-overflow: ellipsis;
77
+      width: 100%;
78
+      text-align: center;
79
+    }
80
+  }
81
+  
82
+  .uni-tr {
83
+    border-bottom: 1rpx solid #e4e7ed;
84
+    
85
+    &:hover {
86
+      background-color: #fafafa;
87
+    }
88
+  }
89
+  
90
+  // 移除默认边框和线条
91
+  .uni-table__header::after {
92
+    display: none;
93
+  }
94
+  
95
+  .uni-table__body::after {
96
+    display: none;
97
+  }
98
+  
99
+  // 最后一列移除右边框
100
+  .uni-tr .uni-th:last-child,
101
+  .uni-tr .uni-td:last-child {
102
+    border-right: none;
103
+  }
104
+  
105
+  // 最后一行移除下边框
106
+  .uni-tr:last-child .uni-td {
107
+    border-bottom: none;
108
+  }
109
+  
110
+  // 支持斑马线样式
111
+  .uni-tr:nth-child(even) {
112
+    background-color: #fafafa;
113
+  }
114
+}
115
+
116
+// 滚动条样式
117
+::v-deep .uni-table ::-webkit-scrollbar {
118
+  width: 6rpx;
119
+  height: 6rpx;
120
+}
121
+
122
+::v-deep .uni-table ::-webkit-scrollbar-track {
123
+  background: #f1f1f1;
124
+}
125
+
126
+::v-deep .uni-table ::-webkit-scrollbar-thumb {
127
+  background: #c1c1c1;
128
+  border-radius: 3rpx;
129
+}
130
+
131
+::v-deep .uni-table ::-webkit-scrollbar-thumb:hover {
132
+  background: #a8a8a8;
133
+}

+ 163 - 0
components/custom-table/index.vue

@@ -0,0 +1,163 @@
1
+<template>
2
+  <scroll-view class="custom-table" scroll-y="true" @scrolltolower="handleScrollLower">
3
+    <uni-table
4
+      ref="tableRef"
5
+      :border="border"
6
+      :stripe="stripe"
7
+      :emptyText="emptyText"
8
+      :loading="loading"
9
+      :type="type"
10
+      @selection-change="handleSelectionChange"
11
+    >
12
+      <!-- 表头 -->
13
+      <uni-tr>
14
+        <!-- 多选列 -->
15
+        <uni-th
16
+          v-if="type === 'selection'"
17
+          type="selection"
18
+          width="60"
19
+        ></uni-th>
20
+        
21
+        <!-- 序号列 -->
22
+        <uni-th
23
+          v-else-if="type === 'index'"
24
+          type="index"
25
+          :index="index"
26
+          width="60"
27
+        ></uni-th>
28
+        
29
+        <!-- 常规列 -->
30
+        <uni-th
31
+          v-for="(column, index) in columns"
32
+          :key="'header-' + index"
33
+          :width="column.width"
34
+          :align="column.align"
35
+          :sortable="column.sortable"
36
+          :sort-method="column.sortMethod"
37
+          :sort-by="column.sortBy"
38
+          :resizable="column.resizable"
39
+        >
40
+          <view>
41
+            <span v-if="column.isRequire" class="custom-table__require">*</span>
42
+            <span>{{ column.label }}</span>
43
+          </view>
44
+        </uni-th>
45
+      </uni-tr>
46
+      
47
+      <!-- 表格内容 -->
48
+      <uni-tr
49
+        v-for="(row, rowIndex) in tableData"
50
+        :key="'row-' + rowIndex"
51
+      >
52
+        <!-- 多选列 -->
53
+        <uni-td v-if="type === 'selection'" type="selection"></uni-td>
54
+        
55
+        <!-- 序号列 -->
56
+        <uni-td v-else-if="type === 'index'" type="index"></uni-td>
57
+        
58
+        <!-- 常规列 -->
59
+        <uni-td
60
+          v-for="(column, colIndex) in columns"
61
+          :key="'cell-' + rowIndex + '-' + colIndex"
62
+          :align="column.align"
63
+          :width="column.width"
64
+        >
65
+          <!-- 自定义单元格内容 -->
66
+          <slot
67
+            :name="'cell-' + column.prop"
68
+            :row="row"
69
+            :rowIndex="rowIndex"
70
+            :column="column"
71
+            :colIndex="colIndex"
72
+          >
73
+            <!-- 默认显示 -->
74
+            <template v-if="column.formatter">
75
+              {{ column.formatter(row, column, row[column.prop], rowIndex) }}
76
+            </template>
77
+            <template v-else>
78
+              {{ row[column.prop] || '-' }}
79
+            </template>
80
+          </slot>
81
+        </uni-td>
82
+      </uni-tr>
83
+    </uni-table>
84
+    
85
+    <!-- 加载更多 -->
86
+    <view v-if="loading && !$attrs.loading" class="custom-table__load-more">
87
+      <u-loading-icon size="18"></u-loading-icon>
88
+      <span class="custom-table__load-more-text">加载中...</span>
89
+    </view>
90
+  </scroll-view>
91
+</template>
92
+
93
+<script>
94
+export default {
95
+  name: 'CustomTable',
96
+  props: {
97
+    tableData: {
98
+      type: Array,
99
+      default: () => []
100
+    },
101
+    columns: {
102
+      type: Array,
103
+      default: () => [],
104
+      validator: (value) => {
105
+        return value.every(item => item.prop && item.label);
106
+      }
107
+    },
108
+    // 是否显示加载中
109
+    loading: {
110
+      type: Boolean,
111
+      default: false
112
+    },
113
+    // 是否带有纵向边框
114
+    border: {
115
+      type: Boolean,
116
+      default: true
117
+    },
118
+    // 是否显示斑马线
119
+    stripe: {
120
+      type: Boolean,
121
+      default: false
122
+    },
123
+    // 表格类型 selection:多选 index:序号
124
+    type: {
125
+      type: String,
126
+      default: '',
127
+      validator: (value) => {
128
+        return ['', 'selection', 'index'].includes(value);
129
+      }
130
+    },
131
+    // 空数据显示的文本
132
+    emptyText: {
133
+      type: String,
134
+      default: '暂无数据'
135
+    },
136
+    // 序号起始值
137
+    index: {
138
+      type: Number,
139
+      default: 1
140
+    }
141
+  },
142
+  data() {
143
+    return {
144
+      scrollPosition: 0 // 滚动位置
145
+    };
146
+  },
147
+  methods: {
148
+    // 滚动事件
149
+    handleScrollLower(e) {
150
+        this.$emit('loadMore');
151
+    },
152
+    
153
+    // 选择项变化
154
+    handleSelectionChange(e) {
155
+      this.$emit('selectionChange', e.detail);
156
+    }
157
+  }
158
+};
159
+</script>
160
+
161
+<style lang="scss" scoped>
162
+@import './index.scss';
163
+</style>

+ 0 - 17
components/form-select-to-page/index.scss

@@ -1,17 +0,0 @@
1
-.form_select_to_page{
2
-    width: 100%;
3
-    display: flex;
4
-    justify-content: flex-end;
5
-    align-items: center;
6
-    font-size: 28rpx;
7
-    font-weight: 600;
8
-    gap: 14rpx;
9
-    &.bottom{
10
-        padding-bottom: 10rpx;
11
-        border-bottom: 2rpx solid #dadbde;
12
-    }
13
-    .none{
14
-        padding-bottom: 0rpx;
15
-        border-bottom: none;
16
-    }
17
-}

+ 0 - 53
components/form-select-to-page/index.vue

@@ -1,53 +0,0 @@
1
-<template>
2
-    <view :class="['form_select_to_page', borderType]" @click="handleClickToPage">
3
-        <view>{{ val }}</view>
4
-        <view @click.stop="clear" v-if="val && isDelete">
5
-            <u-icon size="13" name="close-circle"></u-icon>
6
-        </view>
7
-        <u-icon size="20" name="arrow-right"></u-icon>
8
-    </view>
9
-</template>
10
-<script>
11
-export default {
12
-    components: {
13
-    },
14
-    props: {
15
-        val: {
16
-            type: String || Number,
17
-            default: '' || null,
18
-        },
19
-        url: {
20
-            type: String,
21
-            default: '',
22
-        },
23
-        isDelete: {
24
-            type: Boolean,
25
-            default: false,
26
-        },
27
-        borderType: {   
28
-            type: String,
29
-            default: 'none',//none,bottom
30
-        }
31
-    },
32
-    emits: ['handleClear'],
33
-    data() {
34
-        return {
35
-
36
-        }
37
-    },
38
-    methods: {
39
-        clear(){
40
-            console.log(this.val);
41
-            this.$emit('handleClear');
42
-        },
43
-        handleClickToPage(){
44
-            uni.navigateTo({
45
-                url: this.url
46
-            })
47
-        }
48
-    }
49
-}
50
-</script>
51
-<style lang="scss" scoped>
52
-@import './index.scss';
53
-</style>

+ 6 - 0
main.js

@@ -35,6 +35,11 @@ Vue.use(httpApi, app);
35 35
 import hideNav from "@/utils/hideNav.js";
36 36
 Vue.use(hideNav, app);
37 37
 
38
+// 引入双击指令
39
+import doubleTap from "@/utils/doubleTap.js";
40
+Vue.use(doubleTap, app);
41
+
42
+
38 43
 Vue.prototype.$getDicts = function (dictType, customFlag = true) {
39 44
   return store.dispatch('dict/getDicts', { dictType, customFlag })
40 45
 }
@@ -43,6 +48,7 @@ Vue.prototype.$getDicts = function (dictType, customFlag = true) {
43 48
 import common from "@/utils/common.js";
44 49
 Vue.use(common);
45 50
 
51
+
46 52
 import globalMinxins from "@/mixins";
47 53
 Vue.mixin(globalMinxins);
48 54
 

+ 213 - 2
mock/mockData.js

@@ -778,8 +778,219 @@ const mockDataList = {
778 778
       code: 200,
779 779
       msg: 'success'
780 780
     }
781
-  }
782
-  
781
+  },
782
+  // 仓库模块-假货新增
783
+  '/warehouse/wareHouseFakeAdd': {
784
+    method: 'post',
785
+    data:{
786
+      name:'',//姓名
787
+      idCard:'',//身份证号
788
+      phone:'',//电话
789
+      itemName:'',//物品
790
+      remark:'',//备注
791
+    },
792
+    url: '/prod-api/crm/warehouse/wareHouseFakeAdd',
793
+    delay: 300,
794
+    response: {
795
+      code: 200,
796
+      msg: 'success'
797
+    }
798
+  },
799
+  // 仓库模块-假货编辑
800
+  '/warehouse/wareHouseFakeEdit': {
801
+    method: 'post',
802
+    data:{
803
+      id:'',
804
+      name:'',//姓名
805
+      idCard:'',//身份证号
806
+      phone:'',//电话
807
+      itemName:'',//物品
808
+      remark:'',//备注
809
+    },
810
+    url: '/prod-api/crm/warehouse/wareHouseFakeEdit',
811
+    delay: 300,
812
+    response: {
813
+      code: 200,
814
+      msg: 'success'
815
+    }
816
+  },
817
+  // 仓库模块-假货列表
818
+  '/warehouse/wareHouseFakeList': {
819
+    method: 'post',
820
+    params:{
821
+      pageNum:1,//当前页码
822
+      pageSize:10,//每页数量
823
+    },
824
+    url: '/prod-api/crm/warehouse/wareHouseFakeList',
825
+    delay: 300,
826
+    response: {
827
+      code: 200,
828
+      msg: 'success',
829
+      rows:[
830
+        {
831
+          id:'1',//主键
832
+          name:'张三',//姓名
833
+          idCard:'44030419900101001X',//身份证号
834
+          phone:'13800000000',//电话
835
+          itemName:' Rolex',//物品
836
+          remark:'123456123456123456123456123456',//备注
837
+        },
838
+        {
839
+          id:'1',//主键
840
+          name:'张三',//姓名
841
+          idCard:'44030419900101001X',//身份证号
842
+          phone:'13800000000',//电话
843
+          itemName:' Rolex',//物品
844
+          remark:'123456',//备注
845
+        },
846
+        {
847
+          id:'1',//主键
848
+          name:'张三',//姓名
849
+          idCard:'44030419900101001X',//身份证号
850
+          phone:'13800000000',//电话
851
+          itemName:' Rolex',//物品
852
+          remark:'123456',//备注
853
+        },
854
+        {
855
+          id:'1',//主键
856
+          name:'张三',//姓名
857
+          idCard:'44030419900101001X',//身份证号
858
+          phone:'13800000000',//电话
859
+          itemName:' Rolex',//物品
860
+          remark:'123456',//备注
861
+        },
862
+        {
863
+          id:'1',//主键
864
+          name:'张三',//姓名
865
+          idCard:'44030419900101001X',//身份证号
866
+          phone:'13800000000',//电话
867
+          itemName:' Rolex',//物品
868
+          remark:'123456',//备注
869
+        },
870
+        {
871
+          id:'1',//主键
872
+          name:'张三',//姓名
873
+          idCard:'44030419900101001X',//身份证号
874
+          phone:'13800000000',//电话
875
+          itemName:' Rolex',//物品
876
+          remark:'123456',//备注
877
+        },
878
+        {
879
+          id:'1',//主键
880
+          name:'张三',//姓名
881
+          idCard:'44030419900101001X',//身份证号
882
+          phone:'13800000000',//电话
883
+          itemName:' Rolex',//物品
884
+          remark:'123456',//备注
885
+        },
886
+        {
887
+          id:'1',//主键
888
+          name:'张三',//姓名
889
+          idCard:'44030419900101001X',//身份证号
890
+          phone:'13800000000',//电话
891
+          itemName:' Rolex',//物品
892
+          remark:'123456',//备注
893
+        },
894
+        {
895
+          id:'1',//主键
896
+          name:'张三',//姓名
897
+          idCard:'44030419900101001X',//身份证号
898
+          phone:'13800000000',//电话
899
+          itemName:' Rolex',//物品
900
+          remark:'123456',//备注
901
+        },
902
+        {
903
+          id:'1',//主键
904
+          name:'张三',//姓名
905
+          idCard:'44030419900101001X',//身份证号
906
+          phone:'13800000000',//电话
907
+          itemName:' Rolex',//物品
908
+          remark:'123456',//备注
909
+        },
910
+        {
911
+          id:'1',//主键
912
+          name:'张三',//姓名
913
+          idCard:'44030419900101001X',//身份证号
914
+          phone:'13800000000',//电话
915
+          itemName:' Rolex',//物品
916
+          remark:'123456123456123456123456123456',//备注
917
+        },
918
+        {
919
+          id:'1',//主键
920
+          name:'张三',//姓名
921
+          idCard:'44030419900101001X',//身份证号
922
+          phone:'13800000000',//电话
923
+          itemName:' Rolex',//物品
924
+          remark:'123456',//备注
925
+        },
926
+        {
927
+          id:'1',//主键
928
+          name:'张三',//姓名
929
+          idCard:'44030419900101001X',//身份证号
930
+          phone:'13800000000',//电话
931
+          itemName:' Rolex',//物品
932
+          remark:'123456',//备注
933
+        },
934
+        {
935
+          id:'1',//主键
936
+          name:'张三',//姓名
937
+          idCard:'44030419900101001X',//身份证号
938
+          phone:'13800000000',//电话
939
+          itemName:' Rolex',//物品
940
+          remark:'123456',//备注
941
+        },
942
+        {
943
+          id:'1',//主键
944
+          name:'张三',//姓名
945
+          idCard:'44030419900101001X',//身份证号
946
+          phone:'13800000000',//电话
947
+          itemName:' Rolex',//物品
948
+          remark:'123456',//备注
949
+        },
950
+        {
951
+          id:'1',//主键
952
+          name:'张三',//姓名
953
+          idCard:'44030419900101001X',//身份证号
954
+          phone:'13800000000',//电话
955
+          itemName:' Rolex',//物品
956
+          remark:'123456',//备注
957
+        },
958
+        {
959
+          id:'1',//主键
960
+          name:'张三',//姓名
961
+          idCard:'44030419900101001X',//身份证号
962
+          phone:'13800000000',//电话
963
+          itemName:' Rolex',//物品
964
+          remark:'123456',//备注
965
+        },
966
+        {
967
+          id:'1',//主键
968
+          name:'张三',//姓名
969
+          idCard:'44030419900101001X',//身份证号
970
+          phone:'13800000000',//电话
971
+          itemName:' Rolex',//物品
972
+          remark:'123456',//备注
973
+        },
974
+        {
975
+          id:'1',//主键
976
+          name:'张三',//姓名
977
+          idCard:'44030419900101001X',//身份证号
978
+          phone:'13800000000',//电话
979
+          itemName:' Rolex',//物品
980
+          remark:'123456',//备注
981
+        },
982
+        {
983
+          id:'1',//主键
984
+          name:'张三00',//姓名
985
+          idCard:'44030419900101001X',//身份证号
986
+          phone:'13800000000',//电话
987
+          itemName:' Rolex',//物品
988
+          remark:'123456',//备注
989
+        },
990
+      ],
991
+      total:30,//总条数
992
+    }
993
+  },
783 994
 
784 995
   
785 996
 

+ 8 - 0
pages.json

@@ -190,6 +190,14 @@
190 190
 			}
191 191
 		},
192 192
 		{
193
+			"path" : "pages/wareHouse/components/fakeRegistration",
194
+			"style": {
195
+				"navigationBarTitleText": "假货登记",
196
+				"enablePullDownRefresh": true,
197
+				"navigationStyle": "custom"
198
+			}
199
+		},
200
+		{
193 201
 			"path": "pages/privateClue/index",
194 202
 			"style": {
195 203
 				"navigationBarTitleText": "销售线索",

+ 12 - 9
pages/wareHouse/components/add.vue

@@ -47,7 +47,7 @@
47 47
                     </u-form-item>
48 48
                     <u-form-item label="品牌" required prop="dictLabel" class="u-form-item-row" borderBottom
49 49
                         @click="showBrandList">
50
-                        <FormSelectToPage :val="formData.dictLabel"></FormSelectToPage>
50
+                        <Cell :val="formData.dictLabel"></Cell>
51 51
                         <BrandList ref="brandListRef" @selectedBrand="handleSelectedBrand"></BrandList>
52 52
                     </u-form-item>
53 53
                     <u-form-item label="系列" class="u-form-item-row" borderBottom>
@@ -136,8 +136,7 @@
136 136
                         <u--input v-model="formData.watchYear" placeholder="请输入" clearable border="none"></u--input>
137 137
                     </u-form-item>
138 138
                     <u-form-item label="鉴定人员" class="u-form-item-row" borderBottom @click="identifyingPersonClick">
139
-                        <FormSelectToPage :val="formData.identifyingPerson" :isDelete="true"
140
-                            @handleClear="clear('identifyingPerson')"></FormSelectToPage>
139
+                        <Cell :val="formData.identifyingPerson" :isDelete="true" @handleClear="clear('identifyingPerson')"></Cell>
141 140
                         <PersonPicker ref="identifyingPersonPickerRef" title="请选择鉴定人员"
142 141
                             @selectPerson="handleSelectIdentifyingPerson"></PersonPicker>
143 142
                     </u-form-item>
@@ -149,8 +148,7 @@
149 148
                     <u-form-item label="回收人员" class="u-form-item-row" borderBottom @click="recyclePersonClick">
150 149
                         <!-- <u--input v-model="formData.recyclePerson" disabledColor="#fff" disabled clearable
151 150
                             border="none"></u--input> -->
152
-                        <FormSelectToPage :val="formData.recyclePerson" :isDelete="true"
153
-                            @handleClear="clear('recyclePerson')"></FormSelectToPage>
151
+                        <Cell :val="formData.recyclePerson" :isDelete="true" @handleClear="clear('recyclePerson')"></Cell>
154 152
                         <PersonPicker ref="recyclePersonPickerRef" title="请选择回收人员"
155 153
                             @selectPerson="handleSelectRecyclePerson"></PersonPicker>
156 154
                     </u-form-item>
@@ -170,8 +168,7 @@
170 168
                     </u-form-item>
171 169
                     <u-form-item label="回收时间" required prop="recycleTime" class="u-form-item-row" borderBottom
172 170
                         @click="clickRecycleTimeRow">
173
-                        <FormSelectToPage :val="formData.recycleTime" @deleteItem.stop="clear('recycleTime')">
174
-                        </FormSelectToPage>
171
+                        <Cell :val="formData.recycleTime"></Cell>
175 172
                         <u-datetime-picker @confirm="confirmRecycleTime" @close="closeRecycleTimePicker"
176 173
                             @cancel="closeRecycleTimePicker" :show="recycleTimeShow" v-model="formData.recycleTime"
177 174
                             mode="date"></u-datetime-picker>
@@ -243,7 +240,7 @@
243 240
 </template>
244 241
 <script>
245 242
 import TabSelect from '@/components/custom-tab-select/index.vue'
246
-import FormSelectToPage from '@/components/form-select-to-page/index.vue'
243
+import Cell from '@/components/custom-cell/index.vue'
247 244
 import BrandList from '@/components/brand-list/index.vue'
248 245
 import ImgsRowScroll from '@/components/imgs-row-scroll/index.vue'
249 246
 import PersonPicker from '@/components/person-picker/index.vue'
@@ -251,7 +248,7 @@ import PersonPicker from '@/components/person-picker/index.vue'
251 248
 export default {
252 249
     components: {
253 250
         TabSelect,
254
-        FormSelectToPage,
251
+        Cell,
255 252
         BrandList,
256 253
         ImgsRowScroll,
257 254
         PersonPicker
@@ -546,6 +543,12 @@ export default {
546 543
         },
547 544
         // 清空输入框
548 545
         clear(key) {
546
+            // 品牌
547
+            if (key == 'dictLabel') {
548
+                this.formData.dictLabel = '';
549
+                this.formData.dictValue = '';
550
+                return;
551
+            }
549 552
             // 鉴定人
550 553
             if (key == 'identifyingPerson') {
551 554
                 this.formData.identifyingPerson = '';

+ 181 - 0
pages/wareHouse/components/fakeRegistration.vue

@@ -0,0 +1,181 @@
1
+<template>
2
+  <div class="fake_registration">
3
+    <u-navbar class="nav-bar" title="假货登记" :autoBack="true" :placeholder="true" v-hideNav></u-navbar>
4
+    <view class="fake_table_wrap">
5
+      <view class="btn_wrap">
6
+        <u-button :type="(!isAdd && !isEdit) ? 'primary' : 'error'" :icon="(!isAdd && !isEdit) ? 'plus' : 'close'"
7
+          size="mini" :text="(!isAdd && !isEdit) ? '新增' : '取消'"
8
+          @click="(!isAdd && !isEdit) ? handleAdd() : handleCancle()"></u-button>
9
+        <u-button v-if="isAdd || isEdit" type="primary" size="mini" icon="checkmark" text="确定"
10
+          @click="handleSubmit"></u-button>
11
+      </view>
12
+      <view class="custom-table__body">
13
+        <Table ref="customTable" :tableData="tableData" :columns="columns" stripe @loadMore="handleLoadMore">
14
+          <template #cell-name="{ row, rowIndex }">
15
+            <view v-double-tap="() => editCell(row, rowIndex)">
16
+              <u--input v-if="row.edit" border="surround" v-model="row.name"></u--input>
17
+              <view v-else>{{ row.name }}</view>
18
+            </view>
19
+          </template>
20
+          <template #cell-idCard="{ row, rowIndex }">
21
+            <view v-double-tap="() => editCell(row, rowIndex)">
22
+              <u--input v-if="row.edit" border="surround" v-model="row.idCard"></u--input>
23
+              <view v-else>{{ row.idCard }}</view>
24
+            </view>
25
+          </template>
26
+          <template #cell-phone="{ row, rowIndex }">
27
+            <view v-double-tap="() => editCell(row, rowIndex)"">
28
+            <u--input v-if="row.edit" border="surround" v-model="row.phone"></u--input>
29
+              <view v-else>{{ row.phone }}</view>
30
+            </view>
31
+          </template>
32
+          <template #cell-itemName="{ row, rowIndex }">
33
+            <view v-double-tap="() => editCell(row, rowIndex)"">
34
+            <u--input v-if="row.edit" border="surround" v-model="row.itemName"></u--input>
35
+              <view v-else>{{ row.itemName }}</view>
36
+            </view>
37
+          </template>
38
+          <template #cell-remark="{ row, rowIndex }">
39
+            <view v-double-tap="() => editCell(row, rowIndex)"">
40
+            <u--input v-if="row.edit" border="surround" v-model="row.remark"></u--input>
41
+              <view v-else>{{ row.remark }}</view>
42
+            </view>
43
+          </template>
44
+        </Table>
45
+      </view>
46
+    </view>
47
+  </div>
48
+</template>
49
+
50
+<script>
51
+import Table from '@/components/custom-table/index.vue'
52
+export default {
53
+  name: 'FakeRegistration',
54
+  components: {
55
+    Table
56
+  },
57
+  data() {
58
+    return {
59
+      tableData: [],
60
+      columns: [
61
+        { label: '姓名', prop: 'name',  isRequire: true },
62
+        { label: '身份证号', prop: 'idCard', isRequire: true},
63
+        { label: '电话', prop: 'phone', isRequire: true },
64
+        { label: '物品', prop: 'itemName', isRequire: true },
65
+        { label: '备注', prop: 'remark' },
66
+      ],
67
+      isAdd: false,
68
+      isEdit: false,
69
+      editIndex: null,
70
+      pageNum: 1,
71
+      pageSize: 10,
72
+      total:0
73
+    }
74
+  },
75
+  mounted() {
76
+    this.getWareHouseFakeList()
77
+  },
78
+  methods: {
79
+    handleLoadMore() {
80
+      if (this.pageNum * this.pageSize >= this.total) {
81
+        uni.$u.toast('没有更多数据了')
82
+        return
83
+      }
84
+      this.pageNum++
85
+      this.getWareHouseFakeList()
86
+    },
87
+    getWareHouseFakeList() {
88
+      uni.$u.api.wareHouseFakeList({
89
+        pageNum: this.pageNum,
90
+        pageSize: this.pageSize,
91
+      }).then(res => {
92
+        if(this.pageNum == 1){
93
+          this.tableData = res.rows
94
+        }else{
95
+          this.tableData = this.tableData.concat(res.rows)
96
+        }
97
+        this.total = res.total
98
+      })
99
+    },
100
+    editCell(row, rowIndex) {
101
+      this.editIndex = rowIndex
102
+      this.$set(this.tableData[rowIndex], 'edit', true);
103
+      this.isEdit = true
104
+    },
105
+    handleSubmit() {
106
+      if (this.isAdd) {
107
+        if (this.checkEmpty(this.tableData[0])) {
108
+          uni.$u.api.wareHouseFakeAdd(this.tableData[0]).then(res => {
109
+            if (res.code == 200) {
110
+              this.$set(this.tableData[0], 'edit', false)
111
+              this.isAdd = false
112
+              uni.$u.toast('新增成功')
113
+            }
114
+          })
115
+        }
116
+      }
117
+      if (this.isEdit) {
118
+        if (this.checkEmpty(this.tableData[this.editIndex])) {
119
+          uni.$u.api.wareHouseFakeEdit(this.tableData[this.editIndex]).then(res => {
120
+            if (res.code == 200) {
121
+              this.$set(this.tableData[this.editIndex], 'edit', false)
122
+              this.isEdit = false
123
+              uni.$u.toast('编辑成功')
124
+            }
125
+          })
126
+        }
127
+      }
128
+    },
129
+    checkEmpty(row) {
130
+      if (row.name == '') {
131
+        uni.$u.toast('请输入姓名')
132
+        return false
133
+      }
134
+      if (row.idCard == '') {
135
+        uni.$u.toast('请输入身份证号')
136
+        return false
137
+      }
138
+      if (row.phone == '') {
139
+        uni.$u.toast('请输入电话')
140
+        return false
141
+      }
142
+      if (row.itemName == '') {
143
+        uni.$u.toast('请输入物品')
144
+        return false
145
+      }
146
+      return true
147
+    },
148
+    addNewRow() {
149
+      this.$refs.customTable.addNewRow();
150
+    },
151
+    handleUpdate(data) {
152
+      console.log('数据更新:', data);
153
+    },
154
+    handleAdd() {
155
+      this.tableData.unshift({
156
+        edit: true,
157
+        name: '',
158
+        idCard: '',
159
+        phone: '',
160
+        itemName: '',
161
+        remark: ''
162
+      })
163
+      this.isAdd = true
164
+    },
165
+    handleCancle() {
166
+      if (this.isAdd) {
167
+        this.tableData.shift(1)
168
+        this.isAdd = false
169
+      }
170
+      if (this.isEdit) {
171
+        this.$set(this.tableData[this.editIndex], 'edit', false)
172
+        this.isEdit = false
173
+      }
174
+    },
175
+  }
176
+}
177
+</script>
178
+
179
+<style lang="scss" scoped>
180
+@import '../styles/fakeRegistration.scss';
181
+</style>

+ 6 - 6
pages/wareHouse/components/searchFilter.vue

@@ -2,7 +2,7 @@
2 2
     <u-popup mode="bottom" :round="10" :show="show" @close="close" @open="open" closeable>
3 3
         <u--form labelPosition="left" :model="formData" ref="uForm">
4 4
             <u-form-item label="品牌" @click="showBrandList" labelWidth="70">
5
-                <FormSelectToPage :val="formData.dictLabel" :isDelete="true" borderType="bottom" @handleClear="clear('dictLabel')"></FormSelectToPage>
5
+                <Cell :val="formData.dictLabel" :isDelete="true" :border="true" @handleClear="clear('dictLabel')"></Cell>
6 6
                 <BrandList ref="brandListRef" @selectedBrand="handleSelectedBrand"></BrandList>
7 7
             </u-form-item>
8 8
             <u-form-item label="价格范围" labelWidth="70">
@@ -14,16 +14,16 @@
14 14
                 <u-input v-model="formData.location" fontSize="14" clearable border="bottom"></u-input>
15 15
             </u-form-item>
16 16
             <u-form-item label="回收时间" labelWidth="70" @click="recycleTimeShow = true">
17
-                <FormSelectToPage :val="formData.recycleTime" :isDelete="true" borderType="bottom" @handleClear="clear('recycleTime')">  </FormSelectToPage>
17
+                <Cell :val="formData.recycleTime" :isDelete="true" :border="true" @handleClear="clear('recycleTime')">  </Cell>
18 18
                 <u-datetime-picker  :show="recycleTimeShow" v-model="recycleTimeDefault" mode="date"  @confirm="confirmRecycleTime" @close="recycleTimeShow = false"
19 19
                             @cancel="recycleTimeShow = false"></u-datetime-picker>
20 20
             </u-form-item>
21 21
             <u-form-item label="回收人员" labelWidth="70" @click="recyclePersonClick">
22
-                <FormSelectToPage :val="formData.recyclePerson" :isDelete="true" borderType="bottom" @handleClear="clear('recyclePerson')"></FormSelectToPage>
22
+                <Cell :val="formData.recyclePerson" :isDelete="true" :border="true" @handleClear="clear('recyclePerson')"></Cell>
23 23
                 <PersonPicker ref="recyclePersonPickerRef" title="请选择回收人员" @selectPerson="handleSelectRecyclePerson"></PersonPicker>
24 24
             </u-form-item>
25 25
             <u-form-item label="鉴定人员" labelWidth="70" @click="identifyingPersonClick">
26
-                <FormSelectToPage :val="formData.identifyingPerson" :isDelete="true" borderType="bottom" @handleClear="clear('identifyingPerson')"></FormSelectToPage>
26
+                <Cell :val="formData.identifyingPerson" :isDelete="true" :border="true" @handleClear="clear('identifyingPerson')"></Cell>
27 27
                 <PersonPicker ref="identifyingPersonPickerRef" title="请选择鉴定人员" @selectPerson="handleSelectIdentifyingPerson"></PersonPicker>
28 28
             </u-form-item>
29 29
             <u-form-item label="商品属性" labelWidth="70">
@@ -38,13 +38,13 @@
38 38
 </template>
39 39
 
40 40
 <script>
41
-import FormSelectToPage from '@/components/form-select-to-page/index.vue'
41
+import Cell from '@/components/custom-cell/index.vue'
42 42
 import BrandList from '@/components/brand-list/index.vue'
43 43
 import PersonPicker from '@/components/person-picker/index.vue'
44 44
 import TabSelect from '@/components/custom-tab-select/index.vue'
45 45
 export default {
46 46
     components: {
47
-        FormSelectToPage,
47
+        Cell,
48 48
         BrandList,
49 49
         PersonPicker,
50 50
         TabSelect,

+ 6 - 1
pages/wareHouse/index.vue

@@ -11,7 +11,7 @@
11 11
 					</view>
12 12
 					<text class="asset-value">{{ wareHouseCard.totalCost }}</text>
13 13
 				</view>
14
-				<u-button class="view-btn" type="text" size="mini">查看财务报表</u-button>
14
+				<u-button class="view-btn" type="text" size="mini" @click="navigateToFakeRegistration">假货登记</u-button>
15 15
 			</view>
16 16
 			<view class="data-cards">
17 17
 				<view class="card-item">
@@ -281,6 +281,11 @@ export default {
281 281
 		openSearchFilter(){
282 282
 			this.$refs.searchFilter.open();
283 283
 		},
284
+		navigateToFakeRegistration() {
285
+			uni.navigateTo({
286
+				url: '/pages/wareHouse/components/fakeRegistration',
287
+			});
288
+		},
284 289
 	},
285 290
 	mounted() {
286 291
 		this.getCard();

+ 28 - 0
pages/wareHouse/styles/fakeRegistration.scss

@@ -0,0 +1,28 @@
1
+.fake_registration{
2
+    padding: 20rpx;
3
+    .fake_table_wrap{
4
+        display: flex;
5
+        flex-direction: column;
6
+        justify-content: flex-start;
7
+        align-items: flex-start;
8
+        gap: 20rpx;
9
+        ::v-deep .u-button{
10
+            width:auto;
11
+        }
12
+        .btn_wrap{
13
+            display: flex;
14
+            gap: 20rpx;
15
+        }
16
+        .custom-table__body{
17
+            height: calc(100vh - 240rpx);
18
+            width: -webkit-fill-available;
19
+            border-radius: 20rpx;
20
+            background-color: #fff;
21
+            overflow-y: auto;
22
+            ::v-deep .custom-table{
23
+                margin:20rpx;
24
+                // width: 100%;
25
+            }
26
+        }
27
+    }
28
+}

+ 35 - 0
uni_modules/uni-table/changelog.md

@@ -0,0 +1,35 @@
1
+## 1.2.9(2025-04-14)
2
+- 修复: 下拉筛选中 toISOString() 引发的时区问题
3
+## 1.2.8(2024-10-15)
4
+- 修复 运行到抖音小程序上出现的问题
5
+## 1.2.7(2024-10-15)
6
+- 修复 微信小程序中的getSystemInfo警告
7
+## 1.2.4(2023-12-19)
8
+- 修复 uni-tr只有一列时minWidth计算错误,列变化实时计算更新
9
+## 1.2.3(2023-03-28)
10
+- 修复 在vue3模式下可能会出现错误的问题
11
+## 1.2.2(2022-11-29)
12
+- 优化 主题样式
13
+## 1.2.1(2022-06-06)
14
+- 修复 微信小程序存在无使用组件的问题
15
+## 1.2.0(2021-11-19)
16
+- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
17
+- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-table](https://uniapp.dcloud.io/component/uniui/uni-table)
18
+## 1.1.0(2021-07-30)
19
+- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
20
+## 1.0.7(2021-07-08)
21
+- 新增 uni-th 支持 date 日期筛选范围
22
+## 1.0.6(2021-07-05)
23
+- 新增 uni-th 支持 range 筛选范围
24
+## 1.0.5(2021-06-28)
25
+- 新增 uni-th 筛选功能
26
+## 1.0.4(2021-05-12)
27
+- 新增 示例地址
28
+- 修复 示例项目缺少组件的Bug
29
+## 1.0.3(2021-04-16)
30
+- 新增 sortable 属性,是否开启单列排序
31
+- 优化 表格多选逻辑
32
+## 1.0.2(2021-03-22)
33
+- uni-tr 添加 disabled 属性,用于 type=selection 时,设置某行是否可由全选按钮控制
34
+## 1.0.1(2021-02-05)
35
+- 调整为uni_modules目录规范

+ 460 - 0
uni_modules/uni-table/components/uni-table/uni-table.vue

@@ -0,0 +1,460 @@
1
+<template>
2
+	<view class="uni-table-scroll" :class="{ 'table--border': border, 'border-none': !noData }">
3
+		<!-- #ifdef H5 -->
4
+		<table class="uni-table" border="0" cellpadding="0" cellspacing="0" :class="{ 'table--stripe': stripe }" :style="{ 'min-width': minWidth + 'px' }">
5
+			<slot></slot>
6
+			<tr v-if="noData" class="uni-table-loading">
7
+				<td class="uni-table-text" :class="{ 'empty-border': border }">{{ emptyText }}</td>
8
+			</tr>
9
+			<view v-if="loading" class="uni-table-mask" :class="{ 'empty-border': border }"><div class="uni-table--loader"></div></view>
10
+		</table>
11
+		<!-- #endif -->
12
+		<!-- #ifndef H5 -->
13
+		<view class="uni-table" :style="{ 'min-width': minWidth + 'px' }" :class="{ 'table--stripe': stripe }">
14
+			<slot></slot>
15
+			<view v-if="noData" class="uni-table-loading">
16
+				<view class="uni-table-text" :class="{ 'empty-border': border }">{{ emptyText }}</view>
17
+			</view>
18
+			<view v-if="loading" class="uni-table-mask" :class="{ 'empty-border': border }"><div class="uni-table--loader"></div></view>
19
+		</view>
20
+		<!-- #endif -->
21
+	</view>
22
+</template>
23
+
24
+<script>
25
+/**
26
+ * Table 表格
27
+ * @description 用于展示多条结构类似的数据
28
+ * @tutorial https://ext.dcloud.net.cn/plugin?id=3270
29
+ * @property {Boolean} 	border 				是否带有纵向边框
30
+ * @property {Boolean} 	stripe 				是否显示斑马线
31
+ * @property {Boolean} 	type 					是否开启多选
32
+ * @property {String} 	emptyText 			空数据时显示的文本内容
33
+ * @property {Boolean} 	loading 			显示加载中
34
+ * @event {Function} 	selection-change 	开启多选时,当选择项发生变化时会触发该事件
35
+ */
36
+export default {
37
+	name: 'uniTable',
38
+	options: {
39
+		// #ifdef MP-TOUTIAO
40
+		virtualHost: false,
41
+		// #endif
42
+		// #ifndef MP-TOUTIAO
43
+		virtualHost: true
44
+		// #endif
45
+	},
46
+	emits:['selection-change'],
47
+	props: {
48
+		data: {
49
+			type: Array,
50
+			default() {
51
+				return []
52
+			}
53
+		},
54
+		// 是否有竖线
55
+		border: {
56
+			type: Boolean,
57
+			default: false
58
+		},
59
+		// 是否显示斑马线
60
+		stripe: {
61
+			type: Boolean,
62
+			default: false
63
+		},
64
+		// 多选
65
+		type: {
66
+			type: String,
67
+			default: ''
68
+		},
69
+		// 没有更多数据
70
+		emptyText: {
71
+			type: String,
72
+			default: '没有更多数据'
73
+		},
74
+		loading: {
75
+			type: Boolean,
76
+			default: false
77
+		},
78
+		rowKey: {
79
+			type: String,
80
+			default: ''
81
+		}
82
+	},
83
+	data() {
84
+		return {
85
+			noData: true,
86
+			minWidth: 0,
87
+			multiTableHeads: []
88
+		}
89
+	},
90
+	watch: {
91
+		loading(val) {},
92
+		data(newVal) {
93
+			let theadChildren = this.theadChildren
94
+			let rowspan = 1
95
+			if (this.theadChildren) {
96
+				rowspan = this.theadChildren.rowspan
97
+			}
98
+
99
+			// this.trChildren.length - rowspan
100
+			this.noData = false
101
+			// this.noData = newVal.length === 0
102
+		}
103
+	},
104
+	created() {
105
+		// 定义tr的实例数组
106
+		this.trChildren = []
107
+		this.thChildren = []
108
+		this.theadChildren = null
109
+		this.backData = []
110
+		this.backIndexData = []
111
+	},
112
+
113
+	methods: {
114
+		isNodata() {
115
+			let theadChildren = this.theadChildren
116
+			let rowspan = 1
117
+			if (this.theadChildren) {
118
+				rowspan = this.theadChildren.rowspan
119
+			}
120
+			this.noData = this.trChildren.length - rowspan <= 0
121
+		},
122
+		/**
123
+		 * 选中所有
124
+		 */
125
+		selectionAll() {
126
+			let startIndex = 1
127
+			let theadChildren = this.theadChildren
128
+			if (!this.theadChildren) {
129
+				theadChildren = this.trChildren[0]
130
+			} else {
131
+				startIndex = theadChildren.rowspan - 1
132
+			}
133
+			let isHaveData = this.data && this.data.length > 0
134
+			theadChildren.checked = true
135
+			theadChildren.indeterminate = false
136
+			this.trChildren.forEach((item, index) => {
137
+				if (!item.disabled) {
138
+					item.checked = true
139
+					if (isHaveData && item.keyValue) {
140
+						const row = this.data.find(v => v[this.rowKey] === item.keyValue)
141
+						if (!this.backData.find(v => v[this.rowKey] === row[this.rowKey])) {
142
+							this.backData.push(row)
143
+						}
144
+					}
145
+					if (index > (startIndex - 1) && this.backIndexData.indexOf(index - startIndex) === -1) {
146
+						this.backIndexData.push(index - startIndex)
147
+					}
148
+				}
149
+			})
150
+			// this.backData = JSON.parse(JSON.stringify(this.data))
151
+			this.$emit('selection-change', {
152
+				detail: {
153
+					value: this.backData,
154
+					index: this.backIndexData
155
+				}
156
+			})
157
+		},
158
+		/**
159
+		 * 用于多选表格,切换某一行的选中状态,如果使用了第二个参数,则是设置这一行选中与否(selected 为 true 则选中)
160
+		 */
161
+		toggleRowSelection(row, selected) {
162
+			// if (!this.theadChildren) return
163
+			row = [].concat(row)
164
+
165
+			this.trChildren.forEach((item, index) => {
166
+				// if (item.keyValue) {
167
+
168
+				const select = row.findIndex(v => {
169
+					//
170
+					if (typeof v === 'number') {
171
+						return v === index - 1
172
+					} else {
173
+						return v[this.rowKey] === item.keyValue
174
+					}
175
+				})
176
+				let ischeck = item.checked
177
+				if (select !== -1) {
178
+					if (typeof selected === 'boolean') {
179
+						item.checked = selected
180
+					} else {
181
+						item.checked = !item.checked
182
+					}
183
+					if (ischeck !== item.checked) {
184
+						this.check(item.rowData||item, item.checked, item.rowData?item.keyValue:null, true)
185
+					}
186
+				}
187
+				// }
188
+			})
189
+			this.$emit('selection-change', {
190
+				detail: {
191
+					value: this.backData,
192
+					index:this.backIndexData
193
+				}
194
+			})
195
+		},
196
+
197
+		/**
198
+		 * 用于多选表格,清空用户的选择
199
+		 */
200
+		clearSelection() {
201
+			let theadChildren = this.theadChildren
202
+			if (!this.theadChildren) {
203
+				theadChildren = this.trChildren[0]
204
+			}
205
+			// if (!this.theadChildren) return
206
+			theadChildren.checked = false
207
+			theadChildren.indeterminate = false
208
+			this.trChildren.forEach(item => {
209
+				// if (item.keyValue) {
210
+					item.checked = false
211
+				// }
212
+			})
213
+			this.backData = []
214
+			this.backIndexData = []
215
+			this.$emit('selection-change', {
216
+				detail: {
217
+					value: [],
218
+					index: []
219
+				}
220
+			})
221
+		},
222
+		/**
223
+		 * 用于多选表格,切换所有行的选中状态
224
+		 */
225
+		toggleAllSelection() {
226
+			let list = []
227
+			let startIndex = 1
228
+			let theadChildren = this.theadChildren
229
+			if (!this.theadChildren) {
230
+				theadChildren = this.trChildren[0]
231
+			} else {
232
+				startIndex = theadChildren.rowspan - 1
233
+			}
234
+			this.trChildren.forEach((item, index) => {
235
+				if (!item.disabled) {
236
+					if (index > (startIndex - 1) ) {
237
+						list.push(index-startIndex)
238
+					}
239
+				}
240
+			})
241
+			this.toggleRowSelection(list)
242
+		},
243
+
244
+		/**
245
+		 * 选中\取消选中
246
+		 * @param {Object} child
247
+		 * @param {Object} check
248
+		 * @param {Object} rowValue
249
+		 */
250
+		check(child, check, keyValue, emit) {
251
+			let theadChildren = this.theadChildren
252
+			if (!this.theadChildren) {
253
+				theadChildren = this.trChildren[0]
254
+			}
255
+
256
+
257
+
258
+			let childDomIndex = this.trChildren.findIndex((item, index) => child === item)
259
+			if(childDomIndex < 0){
260
+				childDomIndex = this.data.findIndex(v=>v[this.rowKey] === keyValue) + 1
261
+			}
262
+			const dataLen = this.trChildren.filter(v => !v.disabled && v.keyValue).length
263
+			if (childDomIndex === 0) {
264
+				check ? this.selectionAll() : this.clearSelection()
265
+				return
266
+			}
267
+
268
+			if (check) {
269
+				if (keyValue) {
270
+					this.backData.push(child)
271
+				}
272
+				this.backIndexData.push(childDomIndex - 1)
273
+			} else {
274
+				const index = this.backData.findIndex(v => v[this.rowKey] === keyValue)
275
+				const idx = this.backIndexData.findIndex(item => item === childDomIndex - 1)
276
+				if (keyValue) {
277
+					this.backData.splice(index, 1)
278
+				}
279
+				this.backIndexData.splice(idx, 1)
280
+			}
281
+
282
+			const domCheckAll = this.trChildren.find((item, index) => index > 0 && !item.checked && !item.disabled)
283
+			if (!domCheckAll) {
284
+				theadChildren.indeterminate = false
285
+				theadChildren.checked = true
286
+			} else {
287
+				theadChildren.indeterminate = true
288
+				theadChildren.checked = false
289
+			}
290
+
291
+			if (this.backIndexData.length === 0) {
292
+				theadChildren.indeterminate = false
293
+			}
294
+
295
+			if (!emit) {
296
+				this.$emit('selection-change', {
297
+					detail: {
298
+						value: this.backData,
299
+						index: this.backIndexData
300
+					}
301
+				})
302
+			}
303
+		}
304
+	}
305
+}
306
+</script>
307
+
308
+<style lang="scss">
309
+$border-color: #ebeef5;
310
+
311
+.uni-table-scroll {
312
+	width: 100%;
313
+	/* #ifndef APP-NVUE */
314
+	overflow-x: auto;
315
+	/* #endif */
316
+}
317
+
318
+.uni-table {
319
+	position: relative;
320
+	width: 100%;
321
+	border-radius: 5px;
322
+	// box-shadow: 0px 0px 3px 1px rgba(0, 0, 0, 0.1);
323
+	background-color: #fff;
324
+	/* #ifndef APP-NVUE */
325
+	box-sizing: border-box;
326
+	display: table;
327
+	overflow-x: auto;
328
+	::v-deep .uni-table-tr:nth-child(n + 2) {
329
+		&:hover {
330
+			background-color: #f5f7fa;
331
+		}
332
+	}
333
+	::v-deep .uni-table-thead {
334
+		.uni-table-tr {
335
+			// background-color: #f5f7fa;
336
+			&:hover {
337
+				background-color:#fafafa;
338
+			}
339
+		}
340
+	}
341
+	/* #endif */
342
+}
343
+
344
+.table--border {
345
+	border: 1px $border-color solid;
346
+	border-right: none;
347
+}
348
+
349
+.border-none {
350
+	/* #ifndef APP-NVUE */
351
+	border-bottom: none;
352
+	/* #endif */
353
+}
354
+
355
+.table--stripe {
356
+	/* #ifndef APP-NVUE */
357
+	::v-deep .uni-table-tr:nth-child(2n + 3) {
358
+		background-color: #fafafa;
359
+	}
360
+	/* #endif */
361
+}
362
+
363
+/* 表格加载、无数据样式 */
364
+.uni-table-loading {
365
+	position: relative;
366
+	/* #ifndef APP-NVUE */
367
+	display: table-row;
368
+	/* #endif */
369
+	height: 50px;
370
+	line-height: 50px;
371
+	overflow: hidden;
372
+	box-sizing: border-box;
373
+}
374
+.empty-border {
375
+	border-right: 1px $border-color solid;
376
+}
377
+.uni-table-text {
378
+	position: absolute;
379
+	right: 0;
380
+	left: 0;
381
+	text-align: center;
382
+	font-size: 14px;
383
+	color: #999;
384
+}
385
+
386
+.uni-table-mask {
387
+	position: absolute;
388
+	top: 0;
389
+	bottom: 0;
390
+	left: 0;
391
+	right: 0;
392
+	background-color: rgba(255, 255, 255, 0.8);
393
+	z-index: 99;
394
+	/* #ifndef APP-NVUE */
395
+	display: flex;
396
+	margin: auto;
397
+	transition: all 0.5s;
398
+	/* #endif */
399
+	justify-content: center;
400
+	align-items: center;
401
+}
402
+
403
+.uni-table--loader {
404
+	width: 30px;
405
+	height: 30px;
406
+	border: 2px solid #aaa;
407
+	// border-bottom-color: transparent;
408
+	border-radius: 50%;
409
+	/* #ifndef APP-NVUE */
410
+	animation: 2s uni-table--loader linear infinite;
411
+	/* #endif */
412
+	position: relative;
413
+}
414
+
415
+@keyframes uni-table--loader {
416
+	0% {
417
+		transform: rotate(360deg);
418
+	}
419
+
420
+	10% {
421
+		border-left-color: transparent;
422
+	}
423
+
424
+	20% {
425
+		border-bottom-color: transparent;
426
+	}
427
+
428
+	30% {
429
+		border-right-color: transparent;
430
+	}
431
+
432
+	40% {
433
+		border-top-color: transparent;
434
+	}
435
+
436
+	50% {
437
+		transform: rotate(0deg);
438
+	}
439
+
440
+	60% {
441
+		border-top-color: transparent;
442
+	}
443
+
444
+	70% {
445
+		border-left-color: transparent;
446
+	}
447
+
448
+	80% {
449
+		border-bottom-color: transparent;
450
+	}
451
+
452
+	90% {
453
+		border-right-color: transparent;
454
+	}
455
+
456
+	100% {
457
+		transform: rotate(-360deg);
458
+	}
459
+}
460
+</style>

+ 34 - 0
uni_modules/uni-table/components/uni-tbody/uni-tbody.vue

@@ -0,0 +1,34 @@
1
+<template>
2
+	<!-- #ifdef H5 -->
3
+	<tbody>
4
+		<slot></slot>
5
+	</tbody>
6
+	<!-- #endif -->
7
+	<!-- #ifndef H5 -->
8
+	<view><slot></slot></view>
9
+	<!-- #endif -->
10
+</template>
11
+
12
+<script>
13
+export default {
14
+	name: 'uniBody',
15
+	options: {
16
+		// #ifdef MP-TOUTIAO
17
+		virtualHost: false,
18
+		// #endif
19
+		// #ifndef MP-TOUTIAO
20
+		virtualHost: true
21
+		// #endif
22
+	},
23
+	data() {
24
+		return {
25
+
26
+		}
27
+	},
28
+	created() {},
29
+	methods: {}
30
+}
31
+</script>
32
+
33
+<style>
34
+</style>

+ 95 - 0
uni_modules/uni-table/components/uni-td/uni-td.vue

@@ -0,0 +1,95 @@
1
+<template>
2
+	<!-- #ifdef H5 -->
3
+	<td class="uni-table-td" :rowspan="rowspan" :colspan="colspan" :class="{'table--border':border}" :style="{width:width + 'px','text-align':align}">
4
+		<slot></slot>
5
+	</td>
6
+	<!-- #endif -->
7
+	<!-- #ifndef H5 -->
8
+	<!-- :class="{'table--border':border}"  -->
9
+	<view class="uni-table-td" :class="{'table--border':border}" :style="{width:width + 'px','text-align':align}">
10
+		<slot></slot>
11
+	</view>
12
+	<!-- #endif -->
13
+
14
+</template>
15
+
16
+<script>
17
+	/**
18
+	 * Td 单元格
19
+	 * @description 表格中的标准单元格组件
20
+	 * @tutorial https://ext.dcloud.net.cn/plugin?id=3270
21
+	 * @property {Number} 	align = [left|center|right]	单元格对齐方式
22
+	 */
23
+	export default {
24
+		name: 'uniTd',
25
+		options: {
26
+			// #ifdef MP-TOUTIAO
27
+			virtualHost: false,
28
+			// #endif
29
+			// #ifndef MP-TOUTIAO
30
+			virtualHost: true
31
+			// #endif
32
+		},
33
+		props: {
34
+			width: {
35
+				type: [String, Number],
36
+				default: ''
37
+			},
38
+			align: {
39
+				type: String,
40
+				default: 'left'
41
+			},
42
+			rowspan: {
43
+				type: [Number,String],
44
+				default: 1
45
+			},
46
+			colspan: {
47
+					type: [Number,String],
48
+				default: 1
49
+			}
50
+		},
51
+		data() {
52
+			return {
53
+				border: false
54
+			};
55
+		},
56
+		created() {
57
+			this.root = this.getTable()
58
+			this.border = this.root.border
59
+		},
60
+		methods: {
61
+			/**
62
+			 * 获取父元素实例
63
+			 */
64
+			getTable() {
65
+				let parent = this.$parent;
66
+				let parentName = parent.$options.name;
67
+				while (parentName !== 'uniTable') {
68
+					parent = parent.$parent;
69
+					if (!parent) return false;
70
+					parentName = parent.$options.name;
71
+				}
72
+				return parent;
73
+			},
74
+		}
75
+	}
76
+</script>
77
+
78
+<style lang="scss">
79
+	$border-color:#EBEEF5;
80
+
81
+	.uni-table-td {
82
+		display: table-cell;
83
+		padding: 8px 10px;
84
+		font-size: 14px;
85
+		border-bottom: 1px $border-color solid;
86
+		font-weight: 400;
87
+		color: #606266;
88
+		line-height: 23px;
89
+		box-sizing: border-box;
90
+	}
91
+
92
+	.table--border {
93
+		border-right: 1px $border-color solid;
94
+	}
95
+</style>

+ 511 - 0
uni_modules/uni-table/components/uni-th/filter-dropdown.vue

@@ -0,0 +1,511 @@
1
+<template>
2
+	<view class="uni-filter-dropdown">
3
+		<view class="dropdown-btn" @click="onDropdown">
4
+			<view class="icon-select" :class="{active: canReset}" v-if="isSelect || isRange"></view>
5
+			<view class="icon-search" :class="{active: canReset}" v-if="isSearch">
6
+				<view class="icon-search-0"></view>
7
+				<view class="icon-search-1"></view>
8
+			</view>
9
+			<view class="icon-calendar" :class="{active: canReset}" v-if="isDate">
10
+				<view class="icon-calendar-0"></view>
11
+				<view class="icon-calendar-1"></view>
12
+			</view>
13
+		</view>
14
+		<view class="uni-dropdown-cover" v-if="isOpened" @click="handleClose"></view>
15
+		<view class="dropdown-popup dropdown-popup-right" v-if="isOpened" @click.stop>
16
+			<!-- select-->
17
+			<view v-if="isSelect" class="list">
18
+				<label class="flex-r a-i-c list-item" v-for="(item,index) in dataList" :key="index"
19
+					@click="onItemClick($event, index)">
20
+					<check-box class="check" :checked="item.checked" />
21
+					<view class="checklist-content">
22
+						<text class="checklist-text" :style="item.styleIconText">{{item[map.text]}}</text>
23
+					</view>
24
+				</label>
25
+			</view>
26
+			<view v-if="isSelect" class="flex-r opera-area">
27
+				<view class="flex-f btn btn-default" :class="{disable: !canReset}" @click="handleSelectReset">
28
+					{{resource.reset}}</view>
29
+				<view class="flex-f btn btn-submit" @click="handleSelectSubmit">{{resource.submit}}</view>
30
+			</view>
31
+			<!-- search -->
32
+			<view v-if="isSearch" class="search-area">
33
+				<input class="search-input" v-model="filterValue" />
34
+			</view>
35
+			<view v-if="isSearch" class="flex-r opera-area">
36
+				<view class="flex-f btn btn-submit" @click="handleSearchSubmit">{{resource.search}}</view>
37
+				<view class="flex-f btn btn-default" :class="{disable: !canReset}" @click="handleSearchReset">
38
+					{{resource.reset}}</view>
39
+			</view>
40
+			<!-- range -->
41
+			<view v-if="isRange">
42
+				<view class="input-label">{{resource.gt}}</view>
43
+				<input class="input" v-model="gtValue" />
44
+				<view class="input-label">{{resource.lt}}</view>
45
+				<input class="input" v-model="ltValue" />
46
+			</view>
47
+			<view v-if="isRange" class="flex-r opera-area">
48
+				<view class="flex-f btn btn-default" :class="{disable: !canReset}" @click="handleRangeReset">
49
+					{{resource.reset}}</view>
50
+				<view class="flex-f btn btn-submit" @click="handleRangeSubmit">{{resource.submit}}</view>
51
+			</view>
52
+			<!-- date -->
53
+			<view v-if="isDate">
54
+				<uni-datetime-picker ref="datetimepicker" :value="dateRange" type="datetimerange" return-type="timestamp" @change="datetimechange" @maskClick="timepickerclose">
55
+					<view></view>
56
+				</uni-datetime-picker>
57
+			</view>
58
+		</view>
59
+	</view>
60
+</template>
61
+
62
+<script>
63
+	import checkBox from '../uni-tr/table-checkbox.vue'
64
+
65
+	const resource = {
66
+		"reset": "重置",
67
+		"search": "搜索",
68
+		"submit": "确定",
69
+		"filter": "筛选",
70
+		"gt": "大于等于",
71
+		"lt": "小于等于",
72
+		"date": "日期范围"
73
+	}
74
+
75
+	const DropdownType = {
76
+		Select: "select",
77
+		Search: "search",
78
+		Range: "range",
79
+		Date: "date",
80
+		Timestamp: "timestamp"
81
+	}
82
+
83
+	export default {
84
+		name: 'FilterDropdown',
85
+		emits:['change'],
86
+		components: {
87
+			checkBox
88
+		},
89
+		options: {
90
+			virtualHost: true
91
+		},
92
+		props: {
93
+			filterType: {
94
+				type: String,
95
+				default: DropdownType.Select
96
+			},
97
+			filterData: {
98
+				type: Array,
99
+				default () {
100
+					return []
101
+				}
102
+			},
103
+			mode: {
104
+				type: String,
105
+				default: 'default'
106
+			},
107
+			map: {
108
+				type: Object,
109
+				default () {
110
+					return {
111
+						text: 'text',
112
+						value: 'value'
113
+					}
114
+				}
115
+			},
116
+			filterDefaultValue: {
117
+				type: [Array,String],
118
+				default () {
119
+					return ""
120
+				}
121
+			}
122
+		},
123
+		computed: {
124
+			canReset() {
125
+				if (this.isSearch) {
126
+					return this.filterValue.length > 0
127
+				}
128
+				if (this.isSelect) {
129
+					return this.checkedValues.length > 0
130
+				}
131
+				if (this.isRange) {
132
+					return (this.gtValue.length > 0 && this.ltValue.length > 0)
133
+				}
134
+				if (this.isDate) {
135
+					return this.dateSelect.length > 0
136
+				}
137
+				return false
138
+			},
139
+			isSelect() {
140
+				return this.filterType === DropdownType.Select
141
+			},
142
+			isSearch() {
143
+				return this.filterType === DropdownType.Search
144
+			},
145
+			isRange() {
146
+				return this.filterType === DropdownType.Range
147
+			},
148
+			isDate() {
149
+				return (this.filterType === DropdownType.Date || this.filterType === DropdownType.Timestamp)
150
+			}
151
+		},
152
+		watch: {
153
+			filterData(newVal) {
154
+				this._copyFilters()
155
+			},
156
+			indeterminate(newVal) {
157
+				this.isIndeterminate = newVal
158
+			}
159
+		},
160
+		data() {
161
+			return {
162
+				resource,
163
+				enabled: true,
164
+				isOpened: false,
165
+				dataList: [],
166
+				filterValue: this.filterDefaultValue,
167
+				checkedValues: [],
168
+				gtValue: '',
169
+				ltValue: '',
170
+				dateRange: [],
171
+				dateSelect: []
172
+			};
173
+		},
174
+		created() {
175
+			this._copyFilters()
176
+		},
177
+		methods: {
178
+			_copyFilters() {
179
+				let dl = JSON.parse(JSON.stringify(this.filterData))
180
+				for (let i = 0; i < dl.length; i++) {
181
+					if (dl[i].checked === undefined) {
182
+						dl[i].checked = false
183
+					}
184
+				}
185
+				this.dataList = dl
186
+			},
187
+			openPopup() {
188
+				this.isOpened = true
189
+				if (this.isDate) {
190
+					this.$nextTick(() => {
191
+						if (!this.dateRange.length) {
192
+							this.resetDate()
193
+						}
194
+						this.$refs.datetimepicker.show()
195
+					})
196
+				}
197
+			},
198
+			closePopup() {
199
+				this.isOpened = false
200
+			},
201
+			handleClose(e) {
202
+				this.closePopup()
203
+			},
204
+			resetDate() {
205
+				let date = new Date()
206
+				let dateText = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`
207
+				this.dateRange = [dateText + ' 0:00:00', dateText + ' 23:59:59']
208
+			},
209
+			onDropdown(e) {
210
+				this.openPopup()
211
+			},
212
+			onItemClick(e, index) {
213
+				let items = this.dataList
214
+				let listItem = items[index]
215
+				if (listItem.checked === undefined) {
216
+					items[index].checked = true
217
+				} else {
218
+					items[index].checked = !listItem.checked
219
+				}
220
+
221
+				let checkvalues = []
222
+				for (let i = 0; i < items.length; i++) {
223
+					const item = items[i]
224
+					if (item.checked) {
225
+						checkvalues.push(item.value)
226
+					}
227
+				}
228
+				this.checkedValues = checkvalues
229
+			},
230
+			datetimechange(e) {
231
+				this.closePopup()
232
+				this.dateRange = e
233
+				this.dateSelect = e
234
+				this.$emit('change', {
235
+					filterType: this.filterType,
236
+					filter: e
237
+				})
238
+			},
239
+			timepickerclose(e) {
240
+				this.closePopup()
241
+			},
242
+			handleSelectSubmit() {
243
+				this.closePopup()
244
+				this.$emit('change', {
245
+					filterType: this.filterType,
246
+					filter: this.checkedValues
247
+				})
248
+			},
249
+			handleSelectReset() {
250
+				if (!this.canReset) {
251
+					return;
252
+				}
253
+				var items = this.dataList
254
+				for (let i = 0; i < items.length; i++) {
255
+					let item = items[i]
256
+					this.$set(item, 'checked', false)
257
+				}
258
+				this.checkedValues = []
259
+				this.handleSelectSubmit()
260
+			},
261
+			handleSearchSubmit() {
262
+				this.closePopup()
263
+				this.$emit('change', {
264
+					filterType: this.filterType,
265
+					filter: this.filterValue
266
+				})
267
+			},
268
+			handleSearchReset() {
269
+				if (!this.canReset) {
270
+					return;
271
+				}
272
+				this.filterValue = ''
273
+				this.handleSearchSubmit()
274
+			},
275
+			handleRangeSubmit(isReset) {
276
+				this.closePopup()
277
+				this.$emit('change', {
278
+					filterType: this.filterType,
279
+					filter: isReset === true ? [] : [parseInt(this.gtValue), parseInt(this.ltValue)]
280
+				})
281
+			},
282
+			handleRangeReset() {
283
+				if (!this.canReset) {
284
+					return;
285
+				}
286
+				this.gtValue = ''
287
+				this.ltValue = ''
288
+				this.handleRangeSubmit(true)
289
+			}
290
+		}
291
+	}
292
+</script>
293
+
294
+<style lang="scss">
295
+	$uni-primary: #1890ff !default;
296
+	
297
+	.flex-r {
298
+		display: flex;
299
+		flex-direction: row;
300
+	}
301
+
302
+	.flex-f {
303
+		flex: 1;
304
+	}
305
+
306
+	.a-i-c {
307
+		align-items: center;
308
+	}
309
+
310
+	.j-c-c {
311
+		justify-content: center;
312
+	}
313
+
314
+	.icon-select {
315
+		width: 14px;
316
+		height: 16px;
317
+		border: solid 6px transparent;
318
+		border-top: solid 6px #ddd;
319
+		border-bottom: none;
320
+		background-color: #ddd;
321
+		background-clip: content-box;
322
+		box-sizing: border-box;
323
+	}
324
+
325
+	.icon-select.active {
326
+		background-color: $uni-primary;
327
+		border-top-color: $uni-primary;
328
+	}
329
+
330
+	.icon-search {
331
+		width: 12px;
332
+		height: 16px;
333
+		position: relative;
334
+	}
335
+
336
+	.icon-search-0 {
337
+		border: 2px solid #ddd;
338
+		border-radius: 8px;
339
+		width: 7px;
340
+		height: 7px;
341
+	}
342
+
343
+	.icon-search-1 {
344
+		position: absolute;
345
+		top: 8px;
346
+		right: 0;
347
+		width: 1px;
348
+		height: 7px;
349
+		background-color: #ddd;
350
+		transform: rotate(-45deg);
351
+	}
352
+
353
+	.icon-search.active .icon-search-0 {
354
+		border-color: $uni-primary;
355
+	}
356
+
357
+	.icon-search.active .icon-search-1 {
358
+		background-color: $uni-primary;
359
+	}
360
+
361
+	.icon-calendar {
362
+		color: #ddd;
363
+		width: 14px;
364
+		height: 16px;
365
+	}
366
+
367
+	.icon-calendar-0 {
368
+		height: 4px;
369
+		margin-top: 3px;
370
+		margin-bottom: 1px;
371
+		background-color: #ddd;
372
+		border-radius: 2px 2px 1px 1px;
373
+		position: relative;
374
+	}
375
+	.icon-calendar-0:before, .icon-calendar-0:after {
376
+		content: '';
377
+		position: absolute;
378
+		top: -3px;
379
+		width: 4px;
380
+		height: 3px;
381
+		border-radius: 1px;
382
+		background-color: #ddd;
383
+	}
384
+	.icon-calendar-0:before {
385
+		left: 2px;
386
+	}
387
+	.icon-calendar-0:after {
388
+		right: 2px;
389
+	}
390
+
391
+	.icon-calendar-1 {
392
+		height: 9px;
393
+		background-color: #ddd;
394
+		border-radius: 1px 1px 2px 2px;
395
+	}
396
+
397
+	.icon-calendar.active {
398
+		color: $uni-primary;
399
+	}
400
+
401
+	.icon-calendar.active .icon-calendar-0,
402
+	.icon-calendar.active .icon-calendar-1,
403
+	.icon-calendar.active .icon-calendar-0:before,
404
+	.icon-calendar.active .icon-calendar-0:after {
405
+		background-color: $uni-primary;
406
+	}
407
+
408
+	.uni-filter-dropdown {
409
+		position: relative;
410
+		font-weight: normal;
411
+	}
412
+
413
+	.dropdown-popup {
414
+		position: absolute;
415
+		top: 100%;
416
+		background-color: #fff;
417
+		box-shadow: 0 3px 6px -4px #0000001f, 0 6px 16px #00000014, 0 9px 28px 8px #0000000d;
418
+		min-width: 150px;
419
+		z-index: 1000;
420
+	}
421
+
422
+	.dropdown-popup-left {
423
+		left: 0;
424
+	}
425
+
426
+	.dropdown-popup-right {
427
+		right: 0;
428
+	}
429
+
430
+	.uni-dropdown-cover {
431
+		position: fixed;
432
+		left: 0;
433
+		top: 0;
434
+		right: 0;
435
+		bottom: 0;
436
+		background-color: transparent;
437
+		z-index: 100;
438
+	}
439
+
440
+	.list {
441
+		margin-top: 5px;
442
+		margin-bottom: 5px;
443
+	}
444
+
445
+	.list-item {
446
+		padding: 5px 10px;
447
+		text-align: left;
448
+	}
449
+
450
+	.list-item:hover {
451
+		background-color: #f0f0f0;
452
+	}
453
+
454
+	.check {
455
+		margin-right: 5px;
456
+	}
457
+
458
+	.search-area {
459
+		padding: 10px;
460
+	}
461
+
462
+	.search-input {
463
+		font-size: 12px;
464
+		border: 1px solid #f0f0f0;
465
+		border-radius: 3px;
466
+		padding: 2px 5px;
467
+		min-width: 150px;
468
+		text-align: left;
469
+	}
470
+
471
+	.input-label {
472
+		margin: 10px 10px 5px 10px;
473
+		text-align: left;
474
+	}
475
+
476
+	.input {
477
+		font-size: 12px;
478
+		border: 1px solid #f0f0f0;
479
+		border-radius: 3px;
480
+		margin: 10px;
481
+		padding: 2px 5px;
482
+		min-width: 150px;
483
+		text-align: left;
484
+	}
485
+
486
+	.opera-area {
487
+		cursor: default;
488
+		border-top: 1px solid #ddd;
489
+		padding: 5px;
490
+	}
491
+
492
+	.opera-area .btn {
493
+		font-size: 12px;
494
+		border-radius: 3px;
495
+		margin: 5px;
496
+		padding: 4px 4px;
497
+	}
498
+
499
+	.btn-default {
500
+		border: 1px solid #ddd;
501
+	}
502
+
503
+	.btn-default.disable {
504
+		border-color: transparent;
505
+	}
506
+
507
+	.btn-submit {
508
+		background-color: $uni-primary;
509
+		color: #ffffff;
510
+	}
511
+</style>

+ 295 - 0
uni_modules/uni-table/components/uni-th/uni-th.vue

@@ -0,0 +1,295 @@
1
+<template>
2
+	<!-- #ifdef H5 -->
3
+	<th :rowspan="rowspan" :colspan="colspan" class="uni-table-th" :class="{ 'table--border': border }" :style="{ width: customWidth + 'px', 'text-align': align }">
4
+		<view class="uni-table-th-row">
5
+			<view class="uni-table-th-content" :style="{ 'justify-content': contentAlign }" @click="sort">
6
+				<slot></slot>
7
+				<view v-if="sortable" class="arrow-box">
8
+					<text class="arrow up" :class="{ active: ascending }" @click.stop="ascendingFn"></text>
9
+					<text class="arrow down" :class="{ active: descending }" @click.stop="descendingFn"></text>
10
+				</view>
11
+			</view>
12
+			<dropdown v-if="filterType || filterData.length" :filterDefaultValue="filterDefaultValue" :filterData="filterData" :filterType="filterType" @change="ondropdown"></dropdown>
13
+		</view>
14
+	</th>
15
+	<!-- #endif -->
16
+	<!-- #ifndef H5 -->
17
+	<view class="uni-table-th" :class="{ 'table--border': border }" :style="{ width: customWidth + 'px', 'text-align': align }"><slot></slot></view>
18
+	<!-- #endif -->
19
+</template>
20
+
21
+<script>
22
+	// #ifdef H5
23
+	import dropdown from './filter-dropdown.vue'
24
+	// #endif
25
+/**
26
+ * Th 表头
27
+ * @description 表格内的表头单元格组件
28
+ * @tutorial https://ext.dcloud.net.cn/plugin?id=3270
29
+ * @property {Number | String} 	width 	单元格宽度(支持纯数字、携带单位px或rpx)
30
+ * @property {Boolean} 	sortable 					是否启用排序
31
+ * @property {Number} 	align = [left|center|right]	单元格对齐方式
32
+ * @value left   	单元格文字左侧对齐
33
+ * @value center	单元格文字居中
34
+ * @value right		单元格文字右侧对齐
35
+ * @property {Array}	filterData 筛选数据
36
+ * @property {String}	filterType	[search|select] 筛选类型
37
+ * @value search	关键字搜素
38
+ * @value select	条件选择
39
+ * @event {Function} sort-change 排序触发事件
40
+ */
41
+export default {
42
+	name: 'uniTh',
43
+	options: {
44
+		// #ifdef MP-TOUTIAO
45
+		virtualHost: false,
46
+		// #endif
47
+		// #ifndef MP-TOUTIAO
48
+		virtualHost: true
49
+		// #endif
50
+	},
51
+	components: {
52
+		// #ifdef H5
53
+		dropdown
54
+		// #endif
55
+	},
56
+	emits:['sort-change','filter-change'],
57
+	props: {
58
+		width: {
59
+			type: [String, Number],
60
+			default: ''
61
+		},
62
+		align: {
63
+			type: String,
64
+			default: 'left'
65
+		},
66
+		rowspan: {
67
+			type: [Number, String],
68
+			default: 1
69
+		},
70
+		colspan: {
71
+			type: [Number, String],
72
+			default: 1
73
+		},
74
+		sortable: {
75
+			type: Boolean,
76
+			default: false
77
+		},
78
+		filterType: {
79
+			type: String,
80
+			default: ""
81
+		},
82
+		filterData: {
83
+			type: Array,
84
+			default () {
85
+				return []
86
+			}
87
+		},
88
+		filterDefaultValue: {
89
+			type: [Array,String],
90
+			default () {
91
+				return ""
92
+			}
93
+		}
94
+	},
95
+	data() {
96
+		return {
97
+			border: false,
98
+			ascending: false,
99
+			descending: false
100
+		}
101
+	},
102
+	computed: {
103
+		// 根据props中的width属性 自动匹配当前th的宽度(px)
104
+		customWidth(){
105
+			if(typeof this.width === 'number'){
106
+				return this.width
107
+			} else if(typeof this.width === 'string') {
108
+				let regexHaveUnitPx = new RegExp(/^[1-9][0-9]*px$/g)
109
+				let regexHaveUnitRpx = new RegExp(/^[1-9][0-9]*rpx$/g)
110
+				let regexHaveNotUnit = new RegExp(/^[1-9][0-9]*$/g)
111
+				if (this.width.match(regexHaveUnitPx) !== null) { // 携带了 px
112
+					return this.width.replace('px', '')
113
+				} else if (this.width.match(regexHaveUnitRpx) !== null) { // 携带了 rpx
114
+					let numberRpx = Number(this.width.replace('rpx', ''))
115
+					// #ifdef MP-WEIXIN
116
+					let widthCoe = uni.getWindowInfo().screenWidth / 750
117
+					// #endif
118
+					// #ifndef MP-WEIXIN
119
+					let widthCoe = uni.getSystemInfoSync().screenWidth / 750
120
+					// #endif
121
+					return Math.round(numberRpx * widthCoe)
122
+				} else if (this.width.match(regexHaveNotUnit) !== null) { // 未携带 rpx或px 的纯数字 String
123
+					return this.width
124
+				} else { // 不符合格式
125
+					return ''
126
+				}
127
+			} else {
128
+				return ''
129
+			}
130
+		},
131
+		contentAlign() {
132
+			let align = 'left'
133
+			switch (this.align) {
134
+				case 'left':
135
+					align = 'flex-start'
136
+					break
137
+				case 'center':
138
+					align = 'center'
139
+					break
140
+				case 'right':
141
+					align = 'flex-end'
142
+					break
143
+			}
144
+			return align
145
+		}
146
+	},
147
+	created() {
148
+		this.root = this.getTable('uniTable')
149
+		this.rootTr = this.getTable('uniTr')
150
+		this.rootTr.minWidthUpdate(this.customWidth ? this.customWidth : 140)
151
+		this.border = this.root.border
152
+		this.root.thChildren.push(this)
153
+	},
154
+	methods: {
155
+		sort() {
156
+			if (!this.sortable) return
157
+			this.clearOther()
158
+			if (!this.ascending && !this.descending) {
159
+				this.ascending = true
160
+				this.$emit('sort-change', { order: 'ascending' })
161
+				return
162
+			}
163
+			if (this.ascending && !this.descending) {
164
+				this.ascending = false
165
+				this.descending = true
166
+				this.$emit('sort-change', { order: 'descending' })
167
+				return
168
+			}
169
+
170
+			if (!this.ascending && this.descending) {
171
+				this.ascending = false
172
+				this.descending = false
173
+				this.$emit('sort-change', { order: null })
174
+			}
175
+		},
176
+		ascendingFn() {
177
+			this.clearOther()
178
+			this.ascending = !this.ascending
179
+			this.descending = false
180
+			this.$emit('sort-change', { order: this.ascending ? 'ascending' : null })
181
+		},
182
+		descendingFn() {
183
+			this.clearOther()
184
+			this.descending = !this.descending
185
+			this.ascending = false
186
+			this.$emit('sort-change', { order: this.descending ? 'descending' : null })
187
+		},
188
+		clearOther() {
189
+			this.root.thChildren.map(item => {
190
+				if (item !== this) {
191
+					item.ascending = false
192
+					item.descending = false
193
+				}
194
+				return item
195
+			})
196
+		},
197
+		ondropdown(e) {
198
+			this.$emit("filter-change", e)
199
+		},
200
+		/**
201
+		 * 获取父元素实例
202
+		 */
203
+		getTable(name) {
204
+			let parent = this.$parent
205
+			let parentName = parent.$options.name
206
+			while (parentName !== name) {
207
+				parent = parent.$parent
208
+				if (!parent) return false
209
+				parentName = parent.$options.name
210
+			}
211
+			return parent
212
+		}
213
+	}
214
+}
215
+</script>
216
+
217
+<style lang="scss">
218
+$border-color: #ebeef5;
219
+$uni-primary: #007aff !default;
220
+
221
+.uni-table-th {
222
+	padding: 12px 10px;
223
+	/* #ifndef APP-NVUE */
224
+	display: table-cell;
225
+	box-sizing: border-box;
226
+	/* #endif */
227
+	font-size: 14px;
228
+	font-weight: bold;
229
+	color: #909399;
230
+	border-bottom: 1px $border-color solid;
231
+}
232
+
233
+.uni-table-th-row {
234
+	/* #ifndef APP-NVUE */
235
+	display: flex;
236
+	/* #endif */
237
+	flex-direction: row;
238
+}
239
+
240
+.table--border {
241
+	border-right: 1px $border-color solid;
242
+}
243
+.uni-table-th-content {
244
+	display: flex;
245
+	align-items: center;
246
+	flex: 1;
247
+}
248
+.arrow-box {
249
+}
250
+.arrow {
251
+	display: block;
252
+	position: relative;
253
+	width: 10px;
254
+	height: 8px;
255
+	// border: 1px red solid;
256
+	left: 5px;
257
+	overflow: hidden;
258
+	cursor: pointer;
259
+}
260
+.down {
261
+	top: 3px;
262
+	::after {
263
+		content: '';
264
+		width: 8px;
265
+		height: 8px;
266
+		position: absolute;
267
+		left: 2px;
268
+		top: -5px;
269
+		transform: rotate(45deg);
270
+		background-color: #ccc;
271
+	}
272
+	&.active {
273
+		::after {
274
+			background-color: $uni-primary;
275
+		}
276
+	}
277
+}
278
+.up {
279
+	::after {
280
+		content: '';
281
+		width: 8px;
282
+		height: 8px;
283
+		position: absolute;
284
+		left: 2px;
285
+		top: 5px;
286
+		transform: rotate(45deg);
287
+		background-color: #ccc;
288
+	}
289
+	&.active {
290
+		::after {
291
+			background-color: $uni-primary;
292
+		}
293
+	}
294
+}
295
+</style>

+ 137 - 0
uni_modules/uni-table/components/uni-thead/uni-thead.vue

@@ -0,0 +1,137 @@
1
+<template>
2
+	<!-- #ifdef H5 -->
3
+	<thead class="uni-table-thead">
4
+		<tr class="uni-table-tr">
5
+			<th :rowspan="rowspan" colspan="1" class="checkbox" :class="{ 'tr-table--border': border }">
6
+				<table-checkbox :indeterminate="indeterminate" :checked="checked"
7
+					@checkboxSelected="checkboxSelected"></table-checkbox>
8
+			</th>
9
+		</tr>
10
+		<slot></slot>
11
+	</thead>
12
+	<!-- #endif -->
13
+	<!-- #ifndef H5 -->
14
+	<view class="uni-table-thead">
15
+		<slot></slot>
16
+	</view>
17
+	<!-- #endif -->
18
+</template>
19
+
20
+<script>
21
+	import tableCheckbox from '../uni-tr/table-checkbox.vue'
22
+	export default {
23
+		name: 'uniThead',
24
+		components: {
25
+			tableCheckbox
26
+		},
27
+		options: {
28
+			// #ifdef MP-TOUTIAO
29
+			virtualHost: false,
30
+			// #endif
31
+			// #ifndef MP-TOUTIAO
32
+			virtualHost: true
33
+			// #endif
34
+		},
35
+		data() {
36
+			return {
37
+				border: false,
38
+				selection: false,
39
+				rowspan: 1,
40
+				indeterminate: false,
41
+				checked: false
42
+			}
43
+		},
44
+		created() {
45
+			this.root = this.getTable()
46
+			// #ifdef H5
47
+			this.root.theadChildren = this
48
+			// #endif
49
+			this.border = this.root.border
50
+			this.selection = this.root.type
51
+		},
52
+		methods: {
53
+			init(self) {
54
+				this.rowspan++
55
+			},
56
+			checkboxSelected(e) {
57
+				this.indeterminate = false
58
+				const backIndexData = this.root.backIndexData
59
+				const data = this.root.trChildren.filter(v => !v.disabled && v.keyValue)
60
+				if (backIndexData.length === data.length) {
61
+					this.checked = false
62
+					this.root.clearSelection()
63
+				} else {
64
+					this.checked = true
65
+					this.root.selectionAll()
66
+				}
67
+			},
68
+			/**
69
+			 * 获取父元素实例
70
+			 */
71
+			getTable(name = 'uniTable') {
72
+				let parent = this.$parent
73
+				let parentName = parent.$options.name
74
+				while (parentName !== name) {
75
+					parent = parent.$parent
76
+					if (!parent) return false
77
+					parentName = parent.$options.name
78
+				}
79
+				return parent
80
+			}
81
+		}
82
+	}
83
+</script>
84
+
85
+<style lang="scss">
86
+	$border-color: #ebeef5;
87
+
88
+	.uni-table-thead {
89
+		display: table-header-group;
90
+	}
91
+
92
+	.uni-table-tr {
93
+		/* #ifndef APP-NVUE */
94
+		display: table-row;
95
+		transition: all 0.3s;
96
+		box-sizing: border-box;
97
+		/* #endif */
98
+		border: 1px red solid;
99
+		background-color: #fafafa;
100
+	}
101
+
102
+	.checkbox {
103
+		padding: 0 8px;
104
+		width: 26px;
105
+		padding-left: 12px;
106
+		/* #ifndef APP-NVUE */
107
+		display: table-cell;
108
+		vertical-align: middle;
109
+		/* #endif */
110
+		color: #333;
111
+		font-weight: 500;
112
+		border-bottom: 1px $border-color solid;
113
+		font-size: 14px;
114
+		// text-align: center;
115
+	}
116
+
117
+	.tr-table--border {
118
+		border-right: 1px $border-color solid;
119
+	}
120
+
121
+	/* #ifndef APP-NVUE */
122
+	.uni-table-tr {
123
+		::v-deep .uni-table-th {
124
+			&.table--border:last-child {
125
+				// border-right: none;
126
+			}
127
+		}
128
+
129
+		::v-deep .uni-table-td {
130
+			&.table--border:last-child {
131
+				// border-right: none;
132
+			}
133
+		}
134
+	}
135
+
136
+	/* #endif */
137
+</style>

+ 179 - 0
uni_modules/uni-table/components/uni-tr/table-checkbox.vue

@@ -0,0 +1,179 @@
1
+<template>
2
+	<view class="uni-table-checkbox" @click="selected">
3
+		<view v-if="!indeterminate" class="checkbox__inner" :class="{'is-checked':isChecked,'is-disable':isDisabled}">
4
+			<view class="checkbox__inner-icon"></view>
5
+		</view>
6
+		<view v-else class="checkbox__inner checkbox--indeterminate">
7
+			<view class="checkbox__inner-icon"></view>
8
+		</view>
9
+	</view>
10
+</template>
11
+
12
+<script>
13
+	export default {
14
+		name: 'TableCheckbox',
15
+		emits:['checkboxSelected'],
16
+		props: {
17
+			indeterminate: {
18
+				type: Boolean,
19
+				default: false
20
+			},
21
+			checked: {
22
+				type: [Boolean,String],
23
+				default: false
24
+			},
25
+			disabled: {
26
+				type: Boolean,
27
+				default: false
28
+			},
29
+			index: {
30
+				type: Number,
31
+				default: -1
32
+			},
33
+			cellData: {
34
+				type: Object,
35
+				default () {
36
+					return {}
37
+				}
38
+			}
39
+		},
40
+		watch:{
41
+			checked(newVal){
42
+				if(typeof this.checked === 'boolean'){
43
+					this.isChecked = newVal
44
+				}else{
45
+					this.isChecked = true
46
+				}
47
+			},
48
+			indeterminate(newVal){
49
+				this.isIndeterminate = newVal
50
+			}
51
+		},
52
+		data() {
53
+			return {
54
+				isChecked: false,
55
+				isDisabled: false,
56
+				isIndeterminate:false
57
+			}
58
+		},
59
+		created() {
60
+			if(typeof this.checked === 'boolean'){
61
+				this.isChecked = this.checked
62
+			}
63
+			this.isDisabled = this.disabled
64
+		},
65
+		methods: {
66
+			selected() {
67
+				if (this.isDisabled) return
68
+				this.isIndeterminate = false
69
+				this.isChecked = !this.isChecked
70
+				this.$emit('checkboxSelected', {
71
+					checked: this.isChecked,
72
+					data: this.cellData
73
+				})
74
+			}
75
+		}
76
+	}
77
+</script>
78
+
79
+<style lang="scss">
80
+	$uni-primary: #007aff !default;
81
+	$border-color: #DCDFE6;
82
+	$disable:0.4;
83
+
84
+	.uni-table-checkbox {
85
+		display: flex;
86
+		flex-direction: row;
87
+		align-items: center;
88
+		justify-content: center;
89
+		position: relative;
90
+		margin: 5px 0;
91
+		cursor: pointer;
92
+
93
+		// 多选样式
94
+		.checkbox__inner {
95
+			/* #ifndef APP-NVUE */
96
+			flex-shrink: 0;
97
+			box-sizing: border-box;
98
+			/* #endif */
99
+			position: relative;
100
+			width: 16px;
101
+			height: 16px;
102
+			border: 1px solid $border-color;
103
+			border-radius: 2px;
104
+			background-color: #fff;
105
+			z-index: 1;
106
+
107
+			.checkbox__inner-icon {
108
+				position: absolute;
109
+				/* #ifdef APP-NVUE */
110
+				top: 2px;
111
+				/* #endif */
112
+				/* #ifndef APP-NVUE */
113
+				top: 2px;
114
+				/* #endif */
115
+				left: 5px;
116
+				height: 7px;
117
+				width: 3px;
118
+				border: 1px solid #fff;
119
+				border-left: 0;
120
+				border-top: 0;
121
+				opacity: 0;
122
+				transform-origin: center;
123
+				transform: rotate(45deg);
124
+				box-sizing: content-box;
125
+			}
126
+
127
+			&.checkbox--indeterminate {
128
+				border-color: $uni-primary;
129
+				background-color: $uni-primary;
130
+
131
+				.checkbox__inner-icon {
132
+					position: absolute;
133
+					opacity: 1;
134
+					transform: rotate(0deg);
135
+					height: 2px;
136
+					top: 0;
137
+					bottom: 0;
138
+					margin: auto;
139
+					left: 0px;
140
+					right: 0px;
141
+					bottom: 0;
142
+					width: auto;
143
+					border: none;
144
+					border-radius: 2px;
145
+					transform: scale(0.5);
146
+					background-color: #fff;
147
+				}
148
+			}
149
+			&:hover{
150
+				border-color: $uni-primary;
151
+			}
152
+			// 禁用
153
+			&.is-disable {
154
+				/* #ifdef H5 */
155
+				cursor: not-allowed;
156
+				/* #endif */
157
+				background-color: #F2F6FC;
158
+				border-color: $border-color;
159
+			}
160
+
161
+			// 选中
162
+			&.is-checked {
163
+				border-color: $uni-primary;
164
+				background-color: $uni-primary;
165
+
166
+				.checkbox__inner-icon {
167
+					opacity: 1;
168
+					transform: rotate(45deg);
169
+				}
170
+
171
+				// 选中禁用
172
+				&.is-disable {
173
+					opacity: $disable;
174
+				}
175
+			}
176
+			
177
+		}
178
+	}
179
+</style>

+ 184 - 0
uni_modules/uni-table/components/uni-tr/uni-tr.vue

@@ -0,0 +1,184 @@
1
+<template>
2
+	<!-- #ifdef H5 -->
3
+	<tr class="uni-table-tr">
4
+		<th v-if="selection === 'selection' && ishead" class="checkbox" :class="{ 'tr-table--border': border }">
5
+			<table-checkbox :checked="checked" :indeterminate="indeterminate" :disabled="disabled"
6
+				@checkboxSelected="checkboxSelected"></table-checkbox>
7
+		</th>
8
+		<slot></slot>
9
+		<!-- <uni-th class="th-fixed">123</uni-th> -->
10
+	</tr>
11
+	<!-- #endif -->
12
+	<!-- #ifndef H5 -->
13
+	<view class="uni-table-tr">
14
+		<view v-if="selection === 'selection' " class="checkbox" :class="{ 'tr-table--border': border }">
15
+			<table-checkbox :checked="checked" :indeterminate="indeterminate" :disabled="disabled"
16
+				@checkboxSelected="checkboxSelected"></table-checkbox>
17
+		</view>
18
+		<slot></slot>
19
+	</view>
20
+	<!-- #endif -->
21
+</template>
22
+
23
+<script>
24
+	import tableCheckbox from './table-checkbox.vue'
25
+	/**
26
+	 * Tr 表格行组件
27
+	 * @description 表格行组件 仅包含 th,td 组件
28
+	 * @tutorial https://ext.dcloud.net.cn/plugin?id=
29
+	 */
30
+	export default {
31
+		name: 'uniTr',
32
+		components: {
33
+			tableCheckbox
34
+		},
35
+		props: {
36
+			disabled: {
37
+				type: Boolean,
38
+				default: false
39
+			},
40
+			keyValue: {
41
+				type: [String, Number],
42
+				default: ''
43
+			}
44
+		},
45
+		options: {
46
+			// #ifdef MP-TOUTIAO
47
+			virtualHost: false,
48
+			// #endif
49
+			// #ifndef MP-TOUTIAO
50
+			virtualHost: true
51
+			// #endif
52
+		},
53
+		data() {
54
+			return {
55
+				value: false,
56
+				border: false,
57
+				selection: false,
58
+				widthThArr: [],
59
+				ishead: true,
60
+				checked: false,
61
+				indeterminate: false
62
+			}
63
+		},
64
+		created() {
65
+			this.root = this.getTable()
66
+			this.head = this.getTable('uniThead')
67
+			if (this.head) {
68
+				this.ishead = false
69
+				this.head.init(this)
70
+			}
71
+			this.border = this.root.border
72
+			this.selection = this.root.type
73
+			this.root.trChildren.push(this)
74
+			const rowData = this.root.data.find(v => v[this.root.rowKey] === this.keyValue)
75
+			if (rowData) {
76
+				this.rowData = rowData
77
+			}
78
+			this.root.isNodata()
79
+		},
80
+		mounted() {
81
+			if (this.widthThArr.length > 0) {
82
+				const selectionWidth = this.selection === 'selection' ? 50 : 0
83
+				this.root.minWidth = Number(this.widthThArr.reduce((a, b) => Number(a) + Number(b))) + selectionWidth;
84
+			}
85
+		},
86
+		// #ifndef VUE3
87
+		destroyed() {
88
+			const index = this.root.trChildren.findIndex(i => i === this)
89
+			this.root.trChildren.splice(index, 1)
90
+			this.root.isNodata()
91
+		},
92
+		// #endif
93
+		// #ifdef VUE3
94
+		unmounted() {
95
+			const index = this.root.trChildren.findIndex(i => i === this)
96
+			this.root.trChildren.splice(index, 1)
97
+			this.root.isNodata()
98
+		},
99
+		// #endif
100
+		methods: {
101
+			minWidthUpdate(width) {
102
+				this.widthThArr.push(width)
103
+				if (this.widthThArr.length > 0) {
104
+					const selectionWidth = this.selection === 'selection' ? 50 : 0;
105
+					this.root.minWidth = Number(this.widthThArr.reduce((a, b) => Number(a) + Number(b))) + selectionWidth;
106
+				}
107
+			},
108
+			// 选中
109
+			checkboxSelected(e) {
110
+				let rootData = this.root.data.find(v => v[this.root.rowKey] === this.keyValue)
111
+				this.checked = e.checked
112
+				this.root.check(rootData || this, e.checked, rootData ? this.keyValue : null)
113
+			},
114
+			change(e) {
115
+				this.root.trChildren.forEach(item => {
116
+					if (item === this) {
117
+						this.root.check(this, e.detail.value.length > 0 ? true : false)
118
+					}
119
+				})
120
+			},
121
+			/**
122
+			 * 获取父元素实例
123
+			 */
124
+			getTable(name = 'uniTable') {
125
+				let parent = this.$parent
126
+				let parentName = parent.$options.name
127
+				while (parentName !== name) {
128
+					parent = parent.$parent
129
+					if (!parent) return false
130
+					parentName = parent.$options.name
131
+				}
132
+				return parent
133
+			}
134
+		}
135
+	}
136
+</script>
137
+
138
+<style lang="scss">
139
+	$border-color: #ebeef5;
140
+
141
+	.uni-table-tr {
142
+		/* #ifndef APP-NVUE */
143
+		display: table-row;
144
+		transition: all 0.3s;
145
+		box-sizing: border-box;
146
+		/* #endif */
147
+	}
148
+
149
+	.checkbox {
150
+		padding: 0 8px;
151
+		width: 26px;
152
+		padding-left: 12px;
153
+		/* #ifndef APP-NVUE */
154
+		display: table-cell;
155
+		vertical-align: middle;
156
+		/* #endif */
157
+		color: #333;
158
+		font-weight: 500;
159
+		border-bottom: 1px $border-color solid;
160
+		font-size: 14px;
161
+		// text-align: center;
162
+	}
163
+
164
+	.tr-table--border {
165
+		border-right: 1px $border-color solid;
166
+	}
167
+
168
+	/* #ifndef APP-NVUE */
169
+	.uni-table-tr {
170
+		::v-deep .uni-table-th {
171
+			&.table--border:last-child {
172
+				// border-right: none;
173
+			}
174
+		}
175
+
176
+		::v-deep .uni-table-td {
177
+			&.table--border:last-child {
178
+				// border-right: none;
179
+			}
180
+		}
181
+	}
182
+
183
+	/* #endif */
184
+</style>

+ 9 - 0
uni_modules/uni-table/i18n/en.json

@@ -0,0 +1,9 @@
1
+{
2
+	"filter-dropdown.reset": "Reset",
3
+	"filter-dropdown.search": "Search",
4
+	"filter-dropdown.submit": "Submit",
5
+	"filter-dropdown.filter": "Filter",
6
+	"filter-dropdown.gt": "Greater or equal to",
7
+	"filter-dropdown.lt": "Less than or equal to",
8
+	"filter-dropdown.date": "Date"
9
+}

+ 9 - 0
uni_modules/uni-table/i18n/es.json

@@ -0,0 +1,9 @@
1
+{
2
+	"filter-dropdown.reset": "Reiniciar",
3
+	"filter-dropdown.search": "Búsqueda",
4
+	"filter-dropdown.submit": "Entregar",
5
+	"filter-dropdown.filter": "Filtrar",
6
+	"filter-dropdown.gt": "Mayor o igual a",
7
+	"filter-dropdown.lt": "Menos que o igual a",
8
+	"filter-dropdown.date": "Fecha"
9
+}

+ 9 - 0
uni_modules/uni-table/i18n/fr.json

@@ -0,0 +1,9 @@
1
+{
2
+	"filter-dropdown.reset": "Réinitialiser",
3
+	"filter-dropdown.search": "Chercher",
4
+	"filter-dropdown.submit": "Soumettre",
5
+	"filter-dropdown.filter": "Filtre",
6
+	"filter-dropdown.gt": "Supérieur ou égal à",
7
+	"filter-dropdown.lt": "Inférieur ou égal à",
8
+	"filter-dropdown.date": "Date"
9
+}

+ 12 - 0
uni_modules/uni-table/i18n/index.js

@@ -0,0 +1,12 @@
1
+import en from './en.json'
2
+import es from './es.json'
3
+import fr from './fr.json'
4
+import zhHans from './zh-Hans.json'
5
+import zhHant from './zh-Hant.json'
6
+export default {
7
+	en,
8
+	es,
9
+	fr,
10
+	'zh-Hans': zhHans,
11
+	'zh-Hant': zhHant
12
+}

+ 9 - 0
uni_modules/uni-table/i18n/zh-Hans.json

@@ -0,0 +1,9 @@
1
+{
2
+	"filter-dropdown.reset": "重置",
3
+	"filter-dropdown.search": "搜索",
4
+	"filter-dropdown.submit": "确定",
5
+	"filter-dropdown.filter": "筛选",
6
+	"filter-dropdown.gt": "大于等于",
7
+	"filter-dropdown.lt": "小于等于",
8
+	"filter-dropdown.date": "日期范围"
9
+}

+ 9 - 0
uni_modules/uni-table/i18n/zh-Hant.json

@@ -0,0 +1,9 @@
1
+{
2
+	"filter-dropdown.reset": "重置",
3
+	"filter-dropdown.search": "搜索",
4
+	"filter-dropdown.submit": "確定",
5
+	"filter-dropdown.filter": "篩選",
6
+	"filter-dropdown.gt": "大於等於",
7
+	"filter-dropdown.lt": "小於等於",
8
+	"filter-dropdown.date": "日期範圍"
9
+}

+ 86 - 0
uni_modules/uni-table/package.json

@@ -0,0 +1,86 @@
1
+{
2
+  "id": "uni-table",
3
+  "displayName": "uni-table 表格",
4
+  "version": "1.2.9",
5
+  "description": "表格组件,多用于展示多条结构类似的数据,如",
6
+  "keywords": [
7
+    "uni-ui",
8
+    "uniui",
9
+    "table",
10
+    "表格"
11
+],
12
+  "repository": "https://github.com/dcloudio/uni-ui",
13
+  "engines": {
14
+    "HBuilderX": ""
15
+  },
16
+  "directories": {
17
+    "example": "../../temps/example_temps"
18
+  },
19
+"dcloudext": {
20
+    "sale": {
21
+      "regular": {
22
+        "price": "0.00"
23
+      },
24
+      "sourcecode": {
25
+        "price": "0.00"
26
+      }
27
+    },
28
+    "contact": {
29
+      "qq": ""
30
+    },
31
+    "declaration": {
32
+      "ads": "无",
33
+      "data": "无",
34
+      "permissions": "无"
35
+    },
36
+    "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui",
37
+    "type": "component-vue"
38
+  },
39
+  "uni_modules": {
40
+    "dependencies": ["uni-scss","uni-datetime-picker"],
41
+    "encrypt": [],
42
+    "platforms": {
43
+      "cloud": {
44
+        "tcb": "y",
45
+        "aliyun": "y",
46
+        "alipay": "n"
47
+      },
48
+      "client": {
49
+        "App": {
50
+            "app-vue": "y",
51
+            "app-nvue": "n",
52
+            "app-harmony": "u",
53
+            "app-uvue": "u"
54
+        },
55
+        "H5-mobile": {
56
+          "Safari": "y",
57
+          "Android Browser": "y",
58
+          "微信浏览器(Android)": "y",
59
+          "QQ浏览器(Android)": "y"
60
+        },
61
+        "H5-pc": {
62
+          "Chrome": "y",
63
+          "IE": "y",
64
+          "Edge": "y",
65
+          "Firefox": "y",
66
+          "Safari": "y"
67
+        },
68
+        "小程序": {
69
+          "微信": "y",
70
+          "阿里": "y",
71
+          "百度": "y",
72
+          "字节跳动": "n",
73
+          "QQ": "y"
74
+        },
75
+        "快应用": {
76
+          "华为": "n",
77
+          "联盟": "n"
78
+        },
79
+        "Vue": {
80
+            "vue2": "y",
81
+            "vue3": "y"
82
+        }
83
+      }
84
+    }
85
+  }
86
+}

+ 13 - 0
uni_modules/uni-table/readme.md

@@ -0,0 +1,13 @@
1
+
2
+
3
+## Table 表单
4
+> 组件名:``uni-table``,代码块: `uTable`。
5
+
6
+用于展示多条结构类似的数据
7
+
8
+### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-table)
9
+#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 
10
+
11
+
12
+
13
+

+ 3 - 0
utils/api.js

@@ -133,6 +133,9 @@ const install = (Vue, vm) => {
133 133
 		wareHouseDown:(data)=>http.post(mockApi+'/warehouse/wareHouseDown',data),//仓库中心-下架商品
134 134
 		wareHouseAdd:(data)=>http.post(mockApi+'/warehouse/wareHouseAdd',data),//仓库中心-新增商品
135 135
 		wareHouseOpenOrder:(data)=>http.post(mockApi+'/warehouse/wareHouseOpenOrder',data),//仓库中心-开单
136
+		wareHouseFakeAdd:(data)=>http.post(mockApi+'/warehouse/wareHouseFakeAdd',data),//仓库中心-假货新增
137
+		wareHouseFakeEdit:(data)=>http.post(mockApi+'/warehouse/wareHouseFakeEdit',data),//仓库中心-假货编辑
138
+		wareHouseFakeList:(params,data)=>http.post(mockApi+'/warehouse/wareHouseFakeList?' + qs.stringify(params), data),//仓库中心-假货列表
136 139
 
137 140
 
138 141
 

+ 42 - 0
utils/doubleTap.js

@@ -0,0 +1,42 @@
1
+const doubleTap = {
2
+  install(Vue) {
3
+    Vue.directive('double-tap', {
4
+      bind(el, binding) {
5
+        let lastTap = 0;
6
+        let timeout = null;
7
+        
8
+        const handleClick = (event) => {
9
+          const now = Date.now();
10
+          const timeDiff = now - lastTap;
11
+          
12
+          if (timeout) clearTimeout(timeout);
13
+          
14
+          if (timeDiff < 300 && timeDiff > 0) {
15
+            // 双击事件
16
+            if (typeof binding.value === 'function') {
17
+              binding.value(event);
18
+            }
19
+            lastTap = 0;
20
+          } else {
21
+            // 设置单击定时器
22
+            timeout = setTimeout(() => {
23
+              lastTap = 0;
24
+            }, 300);
25
+            lastTap = now;
26
+          }
27
+        };
28
+        
29
+        el.addEventListener('click', handleClick);
30
+        el._doubleTapHandler = handleClick;
31
+      },
32
+      
33
+      unbind(el) {
34
+        if (el._doubleTapHandler) {
35
+          el.removeEventListener('click', el._doubleTapHandler);
36
+          delete el._doubleTapHandler;
37
+        }
38
+      }
39
+    });
40
+  }
41
+}
42
+export default doubleTap;