xiaohaizhao 1 рік тому
батько
коміт
c318b38084
8 змінених файлів з 508 додано та 24 видалено
  1. 1 0
      App.vue
  2. 67 0
      components/My_search.vue
  3. 74 0
      components/filtrate-group.vue
  4. 174 0
      components/filtrate.vue
  5. 21 18
      index.html
  6. 4 0
      main.js
  7. 92 6
      packageA/course/index.vue
  8. 75 0
      static/iconfont/iconfont.css

+ 1 - 0
App.vue

@@ -13,6 +13,7 @@ export default {
 <style lang="scss">
 /* 注意要写在第一行,同时给style标签加入lang="scss"属性 */
 @import "uview-ui/index.scss";
+@import "static/iconfont/iconfont.css";
 
 body,
 page {

+ 67 - 0
components/My_search.vue

@@ -0,0 +1,67 @@
+<template>
+    <view class="search-box">
+        <view class="search">
+            <icon class="icon" type="search" size="3.733vw" />
+            <input v-model="value" class="input" confirm-type="search" placeholder-style="font-size:3.733vw;"
+                :placeholder="placeholder" type="text" @confirm="onConfirm">
+            <icon v-if="value" class="icon" type="clear" size="3.733vw" @click="onClear" />
+        </view>
+        <slot />
+    </view>
+</template>
+
+<script>
+export default {
+    props: {
+        placeholder: {
+            type: String,
+            default: "搜索关键字"
+        },
+        onSearch: {
+            type: Function
+        }
+    },
+    data() {
+        return {
+            value: ""
+        }
+    },
+    methods: {
+        onConfirm() {
+            this.$emit("onSearch", this.value)
+        },
+        onClear() {
+            this.value = '';
+            this.$emit("onSearch", this.value)
+        }
+    },
+}
+</script>
+
+<style lang="scss">
+.search-box {
+    display: flex;
+    width: 100%;
+    box-sizing: border-box;
+
+    .search {
+        display: flex;
+        align-items: center;
+        flex: 1;
+        height: 30px;
+        background: #F2F2F2;
+        border-radius: 50px;
+        flex-shrink: 0;
+        margin: 0 !important;
+
+        .icon {
+            padding: 10px;
+        }
+
+        .input {
+            flex: 1;
+            margin: 0 !important;
+        }
+    }
+}
+</style>

+ 74 - 0
components/filtrate-group.vue

@@ -0,0 +1,74 @@
+<template>
+    <view class="group-box">
+        <view class="title" v-if="item.title">{{ item.title }}</view>
+        <view class="options">
+            <view class="option" :class="(option[item.selected] == item.value) ? 'active' : ''" v-for="option in item.rang"
+                :key="option[item.selected]" hover-class="navigator-hover" @click="change(option)">
+                {{ option[item.showKey || item.selected] }}
+            </view>
+        </view>
+    </view>
+</template>
+
+<script>
+export default {
+    props: {
+        item: {
+            type: Object
+        },
+        rowIndex: {
+            type: [String, Number]
+        },
+        onChange: {
+            type: Function
+        }
+    },
+    data() {
+        return {
+            show: true
+        }
+    },
+    methods: {
+        change(option) {
+            this.$emit("onChange", option, this.rowIndex)
+        }
+    },
+}
+</script>
+
+<style lang="scss">
+.group-box {
+    padding: 10px;
+    box-sizing: border-box;
+
+    .title {
+        line-height: 22px;
+        font-family: PingFang SC, PingFang SC;
+        font-weight: bold;
+        font-size: 16px;
+        color: #333333;
+    }
+
+    .options {
+        display: flex;
+        flex-wrap: wrap;
+
+        .option {
+            min-width: 80px;
+            padding: 6px;
+            font-family: PingFang SC, PingFang SC;
+            text-align: center;
+            font-size: 14px;
+            color: #333333;
+            margin: 10px 10px 0 0;
+            background: #F2F2F2;
+            border-radius: 5px;
+        }
+
+        .active {
+            color: #FFFFFF;
+            background: #C30D23;
+        }
+    }
+}
+</style>

+ 174 - 0
components/filtrate.vue

@@ -0,0 +1,174 @@
+<template>
+    <view class="filtrate-box">
+        <view :style="{ position: 'absolute', zIndex: index }">
+            <u-transition :show="show">
+                <view class="shade" catchtouchmove="true" @touchmove.stop.prevent="() => { }" @click="changeShow">
+                    <view @click.stop="">
+                        <scroll-view :style="{ maxHeight: tovw(maxHeight) }" class="scroll-view" scroll-y>
+                            <group v-for="(item, index) in list" :ref="'group' + index" :key="item.key" :item="item"
+                                :rowIndex="index" @onChange="onChange" />
+                        </scroll-view>
+                        <view class="but-box">
+                            <view class="reset" hover-class="navigator-hover" @click="onReset">
+                                重置
+                            </view>
+                            <view class="confirm" hover-class="navigator-hover" @click="onConfirm">
+                                确定
+                            </view>
+                        </view>
+                    </view>
+                </view>
+            </u-transition>
+        </view>
+    </view>
+</template>
+
+<script>
+import group from "./filtrate-group.vue"
+export default {
+    components: { group },
+    props: {
+        zIndex: {
+            type: [String, Number],
+            default: 9
+        },
+        filtrateList: {
+            type: Array,
+            default: [{
+                title: "",//组名称
+                key: 'id',//提交时返回的Key
+                showKey: "",//显示的key
+                selected: "",//选择时选择的字段
+                isAll: false,//true 返回整个对象 false 返回selected选中的value
+                value: "",//提交时选中的value
+                defaultVal: "",//默认值
+                rang: "",//选择的范围
+            }]
+        },
+        arrName: {
+            type: String,
+            default: "filtrateList"
+        },
+        onFiltration: {
+            type: Function
+        }
+    },
+    watch: {
+        filtrateList: function (newVal) {
+            if (newVal) {
+                this.list = JSON.parse(JSON.stringify(newVal))
+            } else {
+
+            }
+        }
+    },
+    data() {
+        return {
+            show: false,
+            maxHeight: 0,
+            index: -99,
+            list: []
+        }
+    },
+    methods: {
+        changeShow() {
+            this.show = !this.show;
+            if (this.show) {
+                this.index = this.zIndex
+                setTimeout(this.setHeight, 10);
+            } else {
+                setTimeout(() => { this.index = -99 }, 150)
+            }
+        },
+        setHeight() {
+            this.getHeight(".filtrate-box", this).then(res => {
+                this.maxHeight = res - 300;
+            });
+        },
+        onChange(option, index) {
+            console.log(option, index)
+            let item = this.list[index];
+            this.$set(item, 'value', option[item.selected]);
+            try {
+                if (item.isAll) item.selectObj = option;
+            } catch (error) { }
+            this.$set(this.list, index, item);
+        },
+        onReset() {
+            let page = getCurrentPages()[getCurrentPages().length - 1];
+            // #ifdef H5
+            this.list = JSON.parse(JSON.stringify(page[this.arrName]))
+            // #endif
+            // #ifndef H5
+            this.list = JSON.parse(JSON.stringify(page.data[this.arrName]))
+            // #endif
+            console.log("重置")
+        },
+        onConfirm() {
+            let obj = {};
+            this.list.forEach(v => {
+                if (v.value || v.defaultVal) {
+                    if (v.isAll) {
+                        obj[v.key] = v.rang.find(s => s[v.selected] == v.value) || v.rang.find(s => s[v.selected] == v.defaultVal);
+                    } else {
+                        obj[v.key] = v.value || v.defaultVal;
+                    }
+                } else {
+                    obj[v.key] = v.rang.find(s => s[v.selected] == v.value || s[v.selected] == v.defaultVal);
+                }
+            })
+            this.$emit("onFiltration", obj)
+            this.changeShow();
+        },
+    },
+}
+</script>
+
+<style lang="scss">
+.filtrate-box {
+    position: relative;
+
+    .scroll-view {
+        width: 100vw;
+        background: #fff;
+    }
+
+    .but-box {
+        display: flex;
+        justify-content: space-between;
+        width: 100vw;
+        padding: 10px;
+        background: #fff;
+        box-sizing: border-box;
+
+        .reset {
+            width: 82px;
+            height: 45px;
+            line-height: 45px;
+            text-align: center;
+            background: #FFFFFF;
+            border-radius: 5px;
+            border: 1px solid #999999;
+        }
+
+        .confirm {
+            width: 263px;
+            height: 45px;
+            text-align: center;
+            line-height: 45px;
+            background: #C30D23;
+            border-radius: 5px;
+            font-size: 16px;
+            color: #FFFFFF;
+        }
+    }
+
+    .shade {
+        position: absolute;
+        top: 0;
+        width: 100vw;
+        height: 9999px;
+        background: rgba($color: #000000, $alpha: .7);
+    }
+}
+</style>

+ 21 - 18
index.html

@@ -1,20 +1,23 @@
 <!DOCTYPE html>
 <html lang="en">
-  <head>
-    <meta charset="UTF-8" />
-    <script>
-      var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') ||
-        CSS.supports('top: constant(a)'))
-      document.write(
-        '<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' +
-        (coverSupport ? ', viewport-fit=cover' : '') + '" />')
-    </script>
-    <title></title>
-    <!--preload-links-->
-    <!--app-context-->
-  </head>
-  <body>
-    <div id="app"><!--app-html--></div>
-    <script type="module" src="/main.js"></script>
-  </body>
-</html>
+
+<head>
+  <meta charset="UTF-8" />
+  <script>
+    var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') ||
+      CSS.supports('top: constant(a)'))
+    document.write(
+      '<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' +
+      (coverSupport ? ', viewport-fit=cover' : '') + '" />')
+  </script>
+  <title></title>
+  <!--preload-links-->
+  <!--app-context-->
+</head>
+
+<body>
+  <div id="app"><!--app-html--></div>
+  <script type="module" src="/main.js"></script>
+</body>
+
+</html>

+ 4 - 0
main.js

@@ -9,6 +9,10 @@ Vue.use(uView);
 //自定义组件
 import My_listbox from './components/My_listbox.vue';
 Vue.component("My_listbox", My_listbox);
+import My_search from './components/My_search.vue';
+Vue.component("My_search", My_search);
+import filtrate from './components/filtrate.vue';
+Vue.component("filtrate", filtrate);
 import appList from './components/appList.vue';
 Vue.component("appList", appList);
 

+ 92 - 6
packageA/course/index.vue

@@ -1,8 +1,19 @@
 <template>
     <view>
-        <view style="height: 10px;">
-
+        <view class="head" catchtouchmove="true" @touchmove.stop.prevent="() => { }">
+            <My_search :value="content.where.condition" @onSearch="onSearch">
+                <view class="filtrate" v-if="filtrateList.length" hover-class="navigator-hover" @click="openFiltrate">
+                    筛选
+                    <text class="iconfont icon-shaixuan" />
+                </view>
+            </My_search>
+            <view class="crumbs">
+                <view class="crumb" v-for="item in crumbs" :key="item.classname">{{ item.classname }}</view>
+            </view>
         </view>
+        <view style="height: 1px;" />
+        <filtrate ref="Filtrate" :filtrateList="filtrateList" @onFiltration="onFiltration" />
+        <view style="height: 9px;" />
         <My_listbox ref="List" @getlist="getList" boxBackground="#fff">
             <view class="list-box">
                 <navigator class="item" v-for="item in list" :key="item.sat_coursewareid"
@@ -25,16 +36,18 @@ export default {
     data() {
         return {
             crumbs: [],
-            types: [],
             list: [],
             "content": {
                 "where": {
                     "condition": "",
                     "sat_courseware_classids": [[]]
                 }
-            }
+            },
+            filtrateList: []
         }
     },
+    computed: {
+    },
     onLoad(options) {
         this.crumbs = [{
             classname: "商学院"
@@ -44,7 +57,7 @@ export default {
         }, {
             classname: "全部",
             parentid: ''
-        },]
+        }]
         this.getType()
         this.getList(true)
     },
@@ -62,7 +75,16 @@ export default {
             }).then(res => {
                 console.log("获取二级列表", res)
                 if (this.cutoff(res.msg)) return;
-                this.types = res.pageNumber == 1 ? res.data : this.types.concat(res.data);
+                this.filtrateList = [{
+                    title: "分类",
+                    key: 'sat_courseware_classids',//提交时返回的Key
+                    showKey: "classname",//显示的key
+                    selected: "sat_courseware_classid",//选择时选择的字段
+                    value: "",//提交时选中的value
+                    defaultVal: "",//返回的默认值
+                    isAll: true,
+                    rang: [{ classname: "全部", sat_courseware_classid: "" }].concat(res.data),//选择的范围
+                }]
             })
         },
         getList(init = false) {
@@ -84,11 +106,75 @@ export default {
                 this.content = this.$refs.List.paging(this.content, res)
             })
         },
+        openFiltrate() {
+            this.$refs.Filtrate.changeShow();
+        },
+        onSearch(condition) {
+            this.content.where.condition = condition;
+            this.getList(true)
+        },
+        onFiltration(e) {
+            this.$set(this.crumbs, 2, {
+                classname: e.sat_courseware_classids.classname,
+                parentid: e.sat_courseware_classids.sat_courseware_classid,
+            })
+            this.getList(true)
+        }
     }
 }
 </script>
 
 <style lang="scss">
+.head {
+    padding: 10px;
+    width: 100%;
+    background: #fff;
+    box-sizing: border-box;
+
+    .filtrate {
+        line-height: 30px;
+        padding: 0 10px;
+        font-family: PingFang SC, PingFang SC;
+        font-size: 14px;
+        color: #333333;
+        border-radius: 3px;
+        margin-left: 10px;
+
+        .iconfont {
+            margin-left: 3px;
+            color: #BBBBBB;
+        }
+    }
+}
+
+.crumbs {
+    display: flex;
+    line-height: 17px;
+    font-family: PingFang SC, PingFang SC;
+    font-size: 12px;
+    flex-wrap: wrap;
+    width: 100%;
+    margin-top: 10px;
+
+    .crumb {
+        flex-shrink: 0;
+
+    }
+
+    .crumb::after {
+        content: ">";
+        padding: 0 2px;
+    }
+
+    .crumb:last-child {
+        font-weight: bold;
+    }
+
+    .crumb:last-child::after {
+        content: "";
+    }
+}
+
 .list-box {
     padding: 10px;
     width: 100vw;

+ 75 - 0
static/iconfont/iconfont.css

@@ -0,0 +1,75 @@
+@font-face {
+    font-family: "iconfont"; /* Project id 4131149 */
+    src: url('//at.alicdn.com/t/c/font_4131149_8ru3hljvpmp.woff2?t=1712018915386') format('woff2'),
+         url('//at.alicdn.com/t/c/font_4131149_8ru3hljvpmp.woff?t=1712018915386') format('woff'),
+         url('//at.alicdn.com/t/c/font_4131149_8ru3hljvpmp.ttf?t=1712018915386') format('truetype');
+  }
+  
+  .iconfont {
+    font-family: "iconfont" !important;
+    font-size: 16px;
+    font-style: normal;
+    -webkit-font-smoothing: antialiased;
+    -moz-osx-font-smoothing: grayscale;
+  }
+  
+  .icon-kehuxingming:before {
+    content: "\e6b9";
+  }
+  
+  .icon-dizhi-bai:before {
+    content: "\e6ba";
+  }
+  
+  .icon-a-dianhuashoujihao:before {
+    content: "\e6bb";
+  }
+  
+  .icon-shaixuan:before {
+    content: "\e6b6";
+  }
+  
+  .icon-tika:before {
+    content: "\e6b7";
+  }
+  
+  .icon-shijian:before {
+    content: "\e6b8";
+  }
+  
+  .icon-a-yuncxuanzhong:before {
+    content: "\e6b4";
+  }
+  
+  .icon-a-yuncweixuanzhong:before {
+    content: "\e6b5";
+  }
+  
+  .icon-zanwushuju:before {
+    content: "\e6b1";
+  }
+  
+  .icon-tonggao:before {
+    content: "\e6b2";
+  }
+  
+  .icon-sousuo:before {
+    content: "\e6b3";
+  }
+  
+  .icon-dianhua:before {
+    content: "\e6b0";
+  }
+  
+  .icon-kefu:before {
+    content: "\e6ac";
+  }
+  
+  .icon-dizhi-hei:before {
+    content: "\e6ae";
+  }
+  
+  .icon-dizhi-hui:before {
+    content: "\e6af";
+  }
+