Browse Source

基础文件

zhaoxiaohai 3 năm trước cách đây
mục cha
commit
b6c4b18be5
43 tập tin đã thay đổi với 2058 bổ sung12 xóa
  1. 8 2
      app.js
  2. 11 9
      app.json
  3. 51 0
      app.wxss
  4. 203 0
      components/Yl_Field/index.js
  5. 9 0
      components/Yl_Field/index.json
  6. 155 0
      components/Yl_Field/index.wxml
  7. 55 0
      components/Yl_Field/index.wxss
  8. 145 0
      components/Yl_Files/index.js
  9. 4 0
      components/Yl_Files/index.json
  10. 74 0
      components/Yl_Files/index.scss
  11. 24 0
      components/Yl_Files/index.wxml
  12. 35 0
      components/Yl_FloatingButton/index.js
  13. 4 0
      components/Yl_FloatingButton/index.json
  14. 4 0
      components/Yl_FloatingButton/index.scss
  15. 4 0
      components/Yl_FloatingButton/index.wxml
  16. 66 0
      components/Yl_FunTabs/index.js
  17. 6 0
      components/Yl_FunTabs/index.json
  18. 12 0
      components/Yl_FunTabs/index.wxml
  19. 67 0
      components/Yl_FunTabs/index.wxss
  20. 201 0
      components/Yl_HeadNav/index.js
  21. 6 0
      components/Yl_HeadNav/index.json
  22. 89 0
      components/Yl_HeadNav/index.scss
  23. 54 0
      components/Yl_HeadNav/index.wxml
  24. 56 0
      components/Yl_ListBox/index.js
  25. 4 0
      components/Yl_ListBox/index.json
  26. 4 0
      components/Yl_ListBox/index.scss
  27. 3 0
      components/Yl_ListBox/index.wxml
  28. 65 0
      components/Yl_Tabbar/index.js
  29. 6 0
      components/Yl_Tabbar/index.json
  30. 21 0
      components/Yl_Tabbar/index.wxml
  31. 80 0
      components/Yl_Tabbar/index.wxss
  32. 29 0
      pages/home/index.js
  33. 3 0
      pages/home/index.json
  34. 0 0
      pages/home/index.scss
  35. 0 0
      pages/home/index.wxml
  36. 4 1
      project.config.json
  37. 63 0
      utils/Api.js
  38. 34 0
      utils/Check.js
  39. 53 0
      utils/CheckFile.js
  40. 48 0
      utils/FormatTheAttachment.js
  41. 13 0
      utils/GetRheRemainingHeight.js
  42. 62 0
      utils/Http.js
  43. 223 0
      utils/md5.js

+ 8 - 2
app.js

@@ -1,4 +1,10 @@
+import {
+	ApiModel
+} from './utils/Api';
+
 App({
-  onLaunch() {},
-  globalData: {}
+	onLaunch() {},
+	globalData: {
+		http: new ApiModel(), //接口文件
+	}
 })

+ 11 - 9
app.json

@@ -1,10 +1,12 @@
 {
-  "pages":[],
-  "window":{
-    "backgroundTextStyle":"light",
-    "navigationBarBackgroundColor": "#fff",
-    "navigationBarTitleText": "Weixin",
-    "navigationBarTextStyle":"black"
-  },
-  "sitemapLocation": "sitemap.json"
-}
+    "pages": [
+        "pages/home/index"
+    ],
+    "window": {
+        "backgroundTextStyle": "light",
+        "navigationBarBackgroundColor": "#085CDF",
+        "navigationBarTitleText": "E-订单",
+        "navigationBarTextStyle": "white"
+    },
+    "sitemapLocation": "sitemap.json"
+}

+ 51 - 0
app.wxss

@@ -0,0 +1,51 @@
+page {
+    /* 颜色 */
+    --primary: #095DE0;
+    --assist: #3874F6;
+    --success: #52C41A;
+    --warning: #FA8C16;
+    --error: #FF3B30;
+    --bgColor: #085CDF;
+    /* 字体 */
+    --FCN: PingFangSC-Regular-, PingFangSC-Regular;
+    --FEN: Arial-Regular, Arial;
+    --Fnumber: HelveticaNeue-, HelveticaNeue;
+    /* 基础默认样式 */
+    font-family: var(--FCN);
+    background-color: #F4F5F7;
+
+    /* 适配苹果手机底部安全距离 */
+    padding-bottom: 0;
+    padding-bottom: constant(safe-area-inset-bottom);
+    padding-bottom: env(safe-area-inset-bottom);
+}
+
+navigator {
+    background: none;
+}
+
+/* 解决view不换行 */
+.multi-line {
+    word-break: break-all;
+    white-space: pre-wrap;
+}
+
+/* 文本行数限制 */
+.line-1 {
+    overflow: hidden;
+    white-space: nowrap;
+    text-overflow: ellipsis;
+}
+
+.line-2 {
+    -webkit-line-clamp: 2;
+}
+
+.line-2 {
+    overflow: hidden;
+    word-break: break-all;
+    text-overflow: ellipsis;
+    display: -webkit-box;
+    -webkit-box-orient: vertical;
+}
+

+ 203 - 0
components/Yl_Field/index.js

@@ -0,0 +1,203 @@
+const verify = require('../../utils/deleteMark');
+Component({
+    externalClasses: [],
+    properties: {
+        form: Array,
+        showAll: {
+            type: Boolean,
+            value: true
+        }, //不显示必填项
+        onConfirm: Function,
+        interrupt: Function, //打断处理,用于条件判断 把form返回到上个页面处理重新传入
+    },
+    options: {
+        multipleSlots: true //允许使用多个slot
+    },
+    methods: {
+        toOptions(e) {
+            const {
+                item
+            } = e.currentTarget.dataset;
+            wx.navigateTo({
+                url: '/packageA/options/index?data=' + JSON.stringify(item),
+            })
+        },
+        route(e) {
+            const {
+                item
+            } = e.currentTarget.dataset;
+            let param = JSON.stringify(item);
+            param += item.radio ? '&radio=true' : '';
+            wx.navigateTo({
+                url: item.url + '?item=' + param,
+            })
+        },
+        /* 处理路由返回结果 */
+        handleRoute(data) {
+            let i = this.data.form.findIndex(v => v.valueName == data.valueName);
+            this.setData({
+                [`form[${i}].value`]: data.value
+            });
+            wx.navigateBack();
+            this.triggerEvent("interrupt", {
+                data,
+                form: this.data.form
+            });
+            setTimeout(() => {
+                this.confirm()
+            }, 100)
+        },
+        /* 改变值 */
+        inputChange(e) {
+            let item = e.target.dataset.item,
+                index = this.data.form.findIndex(v => v.valueName === item.valueName),
+                value = e.detail;
+            //开始校验  //校验规则 不填:不校验  "base":默认校验 "phone":手机号  "mail":邮箱  "正则表达式":以自定义内容为校验标准
+            if (item.checking) {
+                let reg = item.checking;
+                switch (item.checking) {
+                    case 'base':
+                        value = verify.queryStr(value);
+                        break;
+                    case 'phone':
+                        reg = /^1(3[0-9]|4[01456879]|5[0-35-9]|6[2567]|7[0-8]|8[0-9]|9[0-35-9])\d{8}$/;
+                        this.setData({
+                            [`form[${index}].errMsg`]: !reg.test(value) ? '请输入正确11位手机号码' : ''
+                        });
+                        break;
+                    case 'mail':
+                        reg = /^([A-Za-z0-9_\-\.])+\@([A-Za-z0-9_\-\.])+\.([A-Za-z]{2,4})$/;
+                        this.setData({
+                            [`form[${index}].errMsg`]: !reg.test(value) ? '请输入正确的邮箱格式' : ''
+                        });
+                        break;
+                    default:
+                        reg = new RegExp(reg);
+                        this.setData({
+                            [`form[${index}].errMsg`]: !reg.test(value) ? item.hint || '输入文本不符合条件!' : ''
+                        });
+                        break;
+                };
+            };
+            this.setData({
+                [`form[${index}].value`]: value,
+                [`form[${index}].error`]: false,
+            });
+            if (!item.required && value == '') this.setData({
+                [`form[${index}].errMsg`]: "",
+            });
+            this.confirm();
+        },
+        /* 日期,时间 选择器 */
+        bindDateChange(e) {
+            let item = e.target.dataset.item,
+                index = this.data.form.findIndex(v => v.valueName === item.valueName),
+                value = e.detail.value;
+
+            this.setData({
+                [`form[${index}].value`]: value,
+                [`form[${index}].error`]: false,
+            });
+            if (item.interrupt) this.triggerEvent("interrupt", {
+                data: this.data.form[index],
+                form: this.data.form
+            });
+            this.confirm();
+        },
+        /* 时间范围选择器 */
+        rangeDateChange(e) {
+            let item = e.target.dataset.item,
+                i = e.target.dataset.index,
+                index = this.data.form.findIndex(v => v.valueName === item.valueName),
+                value = e.detail.value;
+            this.setData({
+                [`form[${index}].value[${i}]`]: value,
+                [`form[${index}].error`]: false,
+            });
+            this.confirm();
+        },
+        /* 省市县 */
+        bindRegionChange(e) {
+            let item = e.currentTarget.dataset.item,
+                index = this.data.form.findIndex(v => v.valueName === item.valueName),
+                value = e.detail.value;
+            this.setData({
+                [`form[${index}].value`]: value,
+                [`form[${index}].error`]: false,
+            });
+            this.confirm();
+        },
+        /* 自定义选项 */
+        setOption(item) {
+            let i = this.data.form.findIndex(v => v.valueName == item.valueName);
+            this.setData({
+                [`form[${i}].value`]: item.value
+            });
+            this.confirm();
+        },
+        /* 是否完成必填项 */
+        confirm() {
+            this.triggerEvent("onConfirm", this.data.form.some(v => {
+                if (v.type == "dateRange" && v.required) {
+                    return v.value[0] == "" || v.value[1] == "";
+                } else {
+                    return v.required && v.value == '';
+                }
+            }))
+        },
+        /* 性别 */
+        sexChange(e) {
+            let item = e.currentTarget.dataset.item,
+                index = this.data.form.findIndex(v => v.valueName === item.valueName);
+            this.setData({
+                [`form[${index}].value`]: e.detail,
+                [`form[${index}].error`]: false,
+            });
+            this.confirm();
+        },
+        /* 单选 选择器改变 */
+        radioChange(e) {
+            let item = e.currentTarget.dataset.item,
+                index = this.data.form.findIndex(v => v.valueName == item.valueName);
+            this.setData({
+                [`form[${index}].value`]: e.detail,
+                [`form[${index}].error`]: false,
+            });
+            if(item.interrupt) this.triggerEvent("interrupt", {
+                data:this.data.form[index],
+                form: this.data.form
+            });
+            this.confirm();
+        },
+        /* 提交 */
+        submit() {
+            let obj = {},
+                isPass = false;
+            this.data.form.forEach((v, i) => {
+                obj[v.valueName] = v.value;
+                if (v.errMsg != '') {
+                    this.setData({
+                        [`form[${i}].error`]: true
+                    });
+                    isPass = true;
+                }
+            });
+            if (isPass) {
+                wx.showToast({
+                    title: '请检查表单内容',
+                    icon: "none"
+                })
+            } else {
+                return obj;
+            }
+        },
+        /* 查询结果 不验证是否必填 */
+        query() {
+            let obj = {};
+            this.data.form.forEach(v => {
+                obj[v.valueName] = v.value;
+            });
+            return obj;
+        }
+    }
+})

+ 9 - 0
components/Yl_Field/index.json

@@ -0,0 +1,9 @@
+{
+    "component": true,
+    "usingComponents": {
+        "van-field": "@vant/weapp/field/index",
+        "van-transition": "@vant/weapp/transition/index",
+        "van-radio": "@vant/weapp/radio/index",
+        "van-radio-group": "@vant/weapp/radio-group/index"
+    }
+}

+ 155 - 0
components/Yl_Field/index.wxml

@@ -0,0 +1,155 @@
+<view wx:for="{{form}}" wx:key="item.valueName" data-name="{{item.valueName}}">
+    <view hidden="{{ !item.required && !showAll }}">
+        <!-- <van-transition show="{{ item.required || showAll }}" name="fade" custom-class="block"> -->
+        <!-- 日期选择器 -->
+        <view class="picker" wx:if="{{item.type=='date'}}">
+            <view class="label">
+                <text class="need" style="color: {{item.required?'#EE0A24':'rgba(0,0,0,0)'}};">*</text>
+                <text class="text" style="color:{{item.disabled?'#C8C9CC':''}};">{{item.label}}</text>
+            </view>
+            <view style="position: relative;">
+                <view class="picker-slot" wx:if="{{item.slot}}">
+                    <slot name="{{item.slot}}" />
+                </view>
+                <picker mode='date' value="{{item.value}}" disabled="{{item.disabled}}" fields='{{item.fields||"day"}}' start="{{item.start}}" end="{{item.end}}" data-item="{{item}}" bindchange="bindDateChange">
+                    <view class="content">
+                        <text wx:if="{{item.value}}" style="color:{{item.disabled?'#C8C9CC':'#000'}};">{{item.value}}</text>
+                        <text wx:else style="color: {{item.error?'#EE4C4E':''}};">{{item.placeholder}}</text>
+                    </view>
+                </picker>
+                <view wx:if="{{item.errMsg}}" class="error-tips">{{item.errMsg}}</view>
+            </view>
+        </view>
+        <!-- 日期范围选择器 -->
+        <view class="picker" wx:elif="{{item.type=='dateRange'}}">
+            <view class="label">
+                <text class="need" style="color: {{item.required?'#EE0A24':'rgba(0,0,0,0)'}};">*</text>
+                <text class="text" style="color:{{item.disabled?'#C8C9CC':''}};">{{item.label}}</text>
+            </view>
+            <view style="position: relative;">
+                <view class="picker-slot" wx:if="{{item.slot}}">
+                    <slot name="{{item.slot}}" />
+                </view>
+                <view class="content" style="display: flex;">
+                    <picker mode='date' value="{{item.value[0]}}" disabled="{{item.disabled}}" fields='{{item.fields||"day"}}' start="{{item.start}}" end="{{item.end}}" data-item="{{item}}" data-index="0" bindchange="rangeDateChange">
+                        <text wx:if="{{item.value[0]}}" style="color:{{item.disabled?'#C8C9CC':'#000'}};">{{item.value[0]}}</text>
+                        <text wx:else style="color: {{item.error?'#EE4C4E':''}};">{{item.placeholder[0]}}</text>
+                    </picker>
+                    <view style="margin: 0 20rpx;color: #000;">至</view>
+                    <picker mode='date' value="{{item.value[1]}}" disabled="{{item.disabled}}" fields='{{item.fields||"day"}}' start="{{item.value[0]}}" end="{{item.end}}" data-item="{{item}}" data-index="1" bindchange="rangeDateChange">
+                        <text wx:if="{{item.value[1]}}" style="color:{{item.disabled?'#C8C9CC':'#000'}};">{{item.value[1]}}</text>
+                        <text wx:else style="color: {{item.error?'#EE4C4E':''}};">{{item.placeholder[1]}}</text>
+                    </picker>
+                </view>
+                <view wx:if="{{item.errMsg}}" class="error-tips">{{item.errMsg}}</view>
+            </view>
+        </view>
+        
+        <!-- 时间选择器 -->
+        <view class="picker" wx:elif="{{item.type=='time'}}">
+            <view class="label">
+                <text class="need" style="color: {{item.required?'#EE0A24':'rgba(0,0,0,0)'}};">*</text>
+                <text class="text" style="color:{{item.disabled?'#C8C9CC':''}};">{{item.label}}</text>
+            </view>
+            <view style="position: relative;">
+                <view class="picker-slot" wx:if="{{item.slot}}">
+                    <slot name="{{item.slot}}" />
+                </view>
+                <picker mode='time' value="{{item.value}}" disabled="{{item.disabled}}" fields='{{item.fields}}' start="{{item.start}}" end="{{item.end}}" data-item="{{item}}" bindchange="bindDateChange">
+                    <view class="content">
+                        <text wx:if="{{item.value}}" style="color:{{item.disabled?'#C8C9CC':'#000'}};">{{item.value}}</text>
+                        <text wx:else style="color: {{item.error?'#EE4C4E':''}};">{{item.placeholder}}</text>
+                    </view>
+                </picker>
+                <view wx:if="{{item.errMsg}}" class="error-tips">{{item.errMsg}}</view>
+            </view>
+        </view>
+        <!-- 省市县选择器 -->
+        <view class="picker" wx:elif="{{item.type=='region'}}">
+            <view class="label">
+                <text class="need" style="color: {{item.required?'#EE0A24':'rgba(0,0,0,0)'}};">*</text>
+                <text class="text" style="color:{{item.disabled?'#C8C9CC':''}};">{{item.label}}</text>
+            </view>
+            <view style="position: relative;">
+                <view class="picker-slot" wx:if="{{item.slot}}">
+                    <slot name="{{item.slot}}" />
+                </view>
+                <picker mode='region' value="{{item.value}}" disabled="{{item.disabled}}" data-item="{{item}}" bindchange="bindRegionChange">
+                    <view class="content">
+                        <text wx:if="{{item.value.length}}" style="color:{{item.disabled?'#C8C9CC':'#000'}};">{{item.value}}</text>
+                        <text wx:else style="color: {{item.error?'#EE4C4E':''}};">{{item.placeholder}}</text>
+                    </view>
+                </picker>
+                <view wx:if="{{item.errMsg}}" class="error-tips">{{item.errMsg}}</view>
+            </view>
+        </view>
+        <!-- 性别 -->
+        <view class="picker" wx:elif="{{item.type=='sex'}}">
+            <view class="label">
+                <text class="need" style="color: {{item.required?'#EE0A24':'rgba(0,0,0,0)'}};">*</text>
+                <text class="text" style="color:{{item.disabled?'#C8C9CC':''}};">{{item.label}}</text>
+            </view>
+            <view style="position: relative;">
+                <view class="content">
+                    <van-radio-group value="{{ item.value }}" data-item="{{item}}" bind:change="sexChange">
+                        <view style="display: flex;">
+                            <van-radio icon-size='16' custom-class='radio' name="男">男</van-radio>
+                            <van-radio icon-size='16' name="女">女</van-radio>
+                        </view>
+                    </van-radio-group>
+                </view>
+                <view wx:if="{{item.errMsg}}" class="error-tips">{{item.errMsg}}</view>
+            </view>
+        </view>
+        <!-- 单选 选择器 -->
+        <view class="picker" wx:elif="{{item.type=='radio'}}">
+            <view class="label">
+                <text class="need" style="color: {{item.required?'#EE0A24':'rgba(0,0,0,0)'}};">*</text>
+                <text class="text" style="color:{{item.disabled?'#C8C9CC':''}};">{{item.label}}</text>
+            </view>
+            <view style="position: relative;">
+                <view class="content">
+                    <van-radio-group value="{{ item.value }}" data-item="{{item}}" bind:change="radioChange">
+                        <van-radio wx:for="{{item.radioList}}" wx:for-item="it" wx:for-index="i" wx:key="it.name" icon-size="16" custom-class="radio {{i != 0 ? 'radio_margin_top' : '' }}" name="{{it.id}}">{{it.name}}</van-radio>
+                    </van-radio-group>
+                </view>
+                <view wx:if="{{item.errMsg}}" class="error-tips">{{item.errMsg}}</view>
+            </view>
+        </view>
+        <!-- 异步类型选择 -->
+        <view class="picker" wx:elif="{{item.type=='option'}}">
+            <view class="label">
+                <text class="need" style="color: {{item.required?'#EE0A24':'rgba(0,0,0,0)'}};">*</text>
+                <text class="text" style="color:{{item.disabled?'#C8C9CC':''}};">{{item.label}}</text>
+            </view>
+            <view style="position: relative;">
+                <view class="content" style="justify-content: space-between; display: flex; align-items: flex-start;" data-item="{{item}}" bindtap="toOptions">
+                    <text wx:if="{{item.value.length}}" style="color:{{item.disabled?'#C8C9CC':'#000'}};">{{item.value}}</text>
+                    <text wx:else style="color: {{item.error?'#EE4C4E':''}};">{{item.placeholder}}</text>
+                    <van-icon name="arrow" style="flex-shrink: 0; margin-top: 12rpx;" />
+                </view>
+                <view wx:if="{{item.errMsg}}" class="error-tips">{{item.errMsg}}</view>
+            </view>
+        </view>
+        <!-- 跳转路由选择 值使用数组,0保存显示名称,1保存ID -->
+        <view class="picker" wx:elif="{{item.type=='route'}}">
+            <view class="label">
+                <text class="need" style="color: {{item.required?'#EE0A24':'rgba(0,0,0,0)'}};">*</text>
+                <text class="text" style="color:{{item.disabled?'#C8C9CC':''}};">{{item.label}}</text>
+            </view>
+            <view style="position: relative;">
+                <view class="content" style="justify-content: space-between; display: flex; align-items: flex-start;" data-item="{{item}}" bindtap="route">
+                    <text wx:if="{{item.value.length}}" style="color:{{item.disabled?'#C8C9CC':'#000'}};">{{item.value[0]}}</text>
+                    <text wx:else style="color: {{item.error?'#EE4C4E':''}};">{{item.placeholder}}</text>
+                    <van-icon name="arrow" style="flex-shrink: 0; margin-top: 12rpx;" />
+                </view>
+                <view wx:if="{{item.errMsg}}" class="error-tips">{{item.errMsg}}</view>
+            </view>
+        </view>
+        <!-- 输入框 -->
+        <van-field wx:else label="{{item.label}}" required="{{item.required}}" value="{{ item.value }}" placeholder="{{item.placeholder||'请填写'}}" label-class='label-class' type="{{item.type}}" error="{{item.error}}" error-message='{{item.errMsg}}' disabled="{{item.disabled}}" autosize border="{{ false }}" bind:input="inputChange" data-item="{{item}}">
+            <slot wx:if="{{item.slot}}" name="{{item.slot}}" slot='button' />
+        </van-field>
+    </view>
+    <!-- </van-transition> -->
+</view>

+ 55 - 0
components/Yl_Field/index.wxss

@@ -0,0 +1,55 @@
+.label-class {
+  word-break: break-all;
+}
+
+.picker {
+  display: flex;
+  width: 100vw;
+  min-height: 48rpx;
+  background-color: #ffffff;
+  padding: 20rpx 0;
+}
+
+.picker .label .text {
+  display: inline-block;
+  font-size: 28rpx;
+  color: var(--field-label-color, #646566);
+  width: 173.58rpx;
+}
+
+.picker .label .need {
+  font-size: 26rpx;
+  margin-left: 16rpx;
+  margin-right: 4rpx;
+}
+
+.picker .content {
+  width: 480rpx;
+  min-height: 48rpx;
+  line-height: 48rpx;
+  box-sizing: border-box;
+  padding-left: 26rpx;
+  font-size: 28rpx;
+  color: #C8C9CC;
+  word-wrap: break-word;
+}
+
+.error-tips {
+  color: #ee250a;
+  font-size: 24rpx;
+  margin-left: 26rpx;
+}
+
+.picker-slot {
+  position: absolute;
+  height: 48rpx;
+  right: -30rpx;
+}
+
+.radio{
+    margin-right: 26rpx;
+}
+
+.radio_margin_top {
+    margin-top: 10px;
+}

+ 145 - 0
components/Yl_Files/index.js

@@ -0,0 +1,145 @@
+const _Http = getApp().globalData.http;
+import {
+    fileList
+} from "../../utils/matchingFeilType";
+Component({
+    properties: {
+        files: {
+            type: Object,
+            value: {
+                images: [],
+                viewImages: [],
+                videos: [],
+                viewVideos: [],
+                files: []
+            },
+        },
+        delete: Boolean
+    },
+    methods: {
+        /* 预览媒体 */
+        viewMedias(e) {
+            const {
+                index,
+                type
+            } = e.currentTarget.dataset;
+            wx.previewMedia({
+                current: index,
+                sources: type == 'image' ? this.data.files.viewImages : this.data.files.viewVideos,
+            })
+        },
+        /* 预览文档 */
+        viewFlies(e) {
+            const {
+                item
+            } = e.currentTarget.dataset;
+            wx.showLoading({
+                title: '加载中...',
+            })
+            wx.downloadFile({
+                url: item.url,
+                complete({
+                    statusCode,
+                    tempFilePath
+                }) {
+                    if (statusCode != 200) return;
+                    wx.openDocument({
+                        filePath: tempFilePath,
+                        fileType: item.postfix,
+                        showMenu: true,
+                        complete({
+                            errMsg
+                        }) {
+                            wx.hideLoading();
+                            if (errMsg != "openDocument:ok") wx.showToast({
+                                title: '打开失败',
+                                icon: "none"
+                            })
+                        }
+                    })
+                }
+            })
+        },
+        /* 删除文件 */
+        handleDeleteFile(e) {
+            let item = e.currentTarget.dataset.item || e.currentTarget.dataset.item;
+            _Http.basic({
+                "classname": "system.attachment.Attachment",
+                "method": "deleteFileLink",
+                "content": {
+                    "linksids": [item.linksid]
+                }
+            }).then(res => {
+                if (res.msg != '成功') return wx.showToast({
+                    title: res.data,
+                    icon: "none"
+                });
+                let files = this.data.files;
+                switch (item.fileType) {
+                    case "image":
+                        files.images = files.images.filter(v => v.url != item.url);
+                        files.viewImages = files.viewImages.filter(v => v.url != item.url);
+                        break;
+                    case "video":
+                        files.videos = files.videos.filter(v => v.url != item.url);
+                        files.viewVideos = files.viewVideos.filter(v => v.url != item.url);
+                        break;
+                    default:
+                        files.files = files.files.filter(v => v.attachmentid != item.attachmentid);
+                        break;
+                };
+                this.setData({
+                    files
+                });
+            })
+        },
+        /* 处理附件 */
+        handleFiles(arr, init = false) {
+            let files = init ? {
+                    images: [],
+                    viewImages: [],
+                    videos: [],
+                    viewVideos: [],
+                    files: []
+                } : this.data.files,
+                list = fileList(arr);
+            list.forEach(v => {
+                switch (v.fileType) {
+                    case "video":
+                        files.videos.push(v)
+                        files.viewVideos.push({
+                            url: v.url,
+                            type: "video",
+                            poster: v.subfiles[0].url
+                        })
+                        break;
+                    case "image":
+                        files.images.push(v)
+                        files.viewImages.push({
+                            url: v.url,
+                            type: "image"
+                        })
+                        break;
+                    default:
+                        files.files.push(v)
+                        break;
+                }
+            });
+            this.setData({
+                files
+            })
+        },
+        /* 初始化数据 */
+        initData() {
+            this.setData({
+                files: {
+                    images: [],
+                    viewImages: [],
+                    videos: [],
+                    viewVideos: [],
+                    files: []
+                }
+            })
+        },
+    }
+})

+ 4 - 0
components/Yl_Files/index.json

@@ -0,0 +1,4 @@
+{
+    "component": true,
+    "usingComponents": {}
+}

+ 74 - 0
components/Yl_Files/index.scss

@@ -0,0 +1,74 @@
+.media {
+    width: 100%;
+    display: flex;
+    flex-wrap: wrap;
+    margin-top: 20rpx;
+    padding: 0 30rpx;
+    box-sizing: border-box;
+
+    .item {
+        position: relative;
+        width: 158rpx;
+        height: 158rpx;
+        margin-right: 18rpx;
+        margin-bottom: 18rpx;
+        border-radius: 8rpx;
+        overflow: hidden;
+
+        image {
+            width: 100%;
+            height: 100%;
+        }
+
+        .delete {
+            position: absolute;
+            width: 40rpx;
+            height: 40rpx;
+            right: 0;
+            top: 0;
+        }
+
+        .shade {
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            position: absolute;
+            width: 100%;
+            height: 100%;
+            background: rgba(0, 0, 0, 0.2);
+            top: 0;
+            left: 0;
+            color: #ffffff;
+
+        }
+
+    }
+
+    .item:nth-child(4n) {
+        margin-right: 0;
+    }
+
+    .file {
+        display: flex;
+        flex-direction: column;
+        border: 1px solid #CCCCCC;
+        box-sizing: border-box;
+        align-items: center;
+
+        .name {
+            width: 120rpx;
+            font-size: 24rpx;
+            font-family: PingFang SC-Regular, PingFang SC;
+            color: #333333;
+            margin-top: 20rpx;
+            overflow: hidden;
+            white-space: nowrap;
+            text-overflow: ellipsis;
+        }
+
+        .image {
+            height: 58rpx;
+            margin-top: 24rpx;
+        }
+    }
+}

+ 24 - 0
components/Yl_Files/index.wxml

@@ -0,0 +1,24 @@
+<view class="media">
+    <!-- 图片 -->
+    <navigator url="#" class="item" wx:for="{{files.images}}" wx:key="item.attachmentid">
+        <image src="{{item.url}}" data-index="{{index}}" data-type='image' mode="aspectFill" bindtap="viewMedias" />
+        <image wx:if="{{delete}}" class="delete" src="/static/image/delete.png" data-item="{{item}}" bindtap="handleDeleteFile" />
+    </navigator>
+    <!-- 视频 -->
+    <navigator url="#" class="item" wx:for="{{files.videos}}" wx:key="item.attachmentid">
+        <image src="{{item.subfiles[0].url}}" mode="aspectFill" />
+        <view class="shade" data-index="{{index}}" data-type='video' bindtap="viewMedias">
+            <van-icon size='48rpx' name="play" />
+        </view>
+        <image wx:if="{{delete}}" class="delete" src="/static/image/delete.png" data-item="{{item}}" bindtap="handleDeleteFile" />
+    </navigator>
+    <!-- 文件 -->
+    <navigator url="#" class="item file" wx:for="{{files.files}}" wx:key="item.attachmentid" data-item='{{item}}' bindtap="viewFlies">
+        <image class="image" src="{{item.cover}}" mode="heightFix" />
+        <view class="name">
+            {{item.document}}
+        </view>
+        <image wx:if="{{delete}}" class="delete" src="/static/image/delete.png" data-item="{{item}}" catchtap="handleDeleteFile" />
+    </navigator>
+</view>
+<!--  list="{{files.files}}" -->

+ 35 - 0
components/Yl_FloatingButton/index.js

@@ -0,0 +1,35 @@
+Component({
+  properties: {
+    radius: Number, //半径 单位px
+    useSlot: Boolean
+  },
+  data: {
+    top: "550px",
+    left: "345px",
+    viewHeight: null
+  },
+  lifetimes: {
+    attached: function () {
+      let that = this;
+      wx.getSystemInfo({
+        success: (res => that.setData({
+          viewHeight: res.windowHeight
+        }))
+      });
+    },
+  },
+  methods: {
+    viewTouchMove(e) {
+      let left = e.touches[0].pageX;
+      if (left > (375 - this.data.radius)) left = 375 - (this.data.radius / 2);
+      if (left < 0 + this.data.radius) left = 0 + this.data.radius;
+      let top = e.touches[0].pageY;
+      if (top < 0 + this.data.radius) top = 0 + this.data.radius;
+      if (top > this.data.viewHeight - this.data.radius) top = this.data.viewHeight - this.data.radius;
+      this.setData({
+        left: left + 'px',
+        top: top + 'px'
+      })
+    }
+  }
+})

+ 4 - 0
components/Yl_FloatingButton/index.json

@@ -0,0 +1,4 @@
+{
+    "component": true,
+    "usingComponents": {}
+}

+ 4 - 0
components/Yl_FloatingButton/index.scss

@@ -0,0 +1,4 @@
+.float-box{
+    position: absolute;
+    z-index: 99;
+}

+ 4 - 0
components/Yl_FloatingButton/index.wxml

@@ -0,0 +1,4 @@
+<view class="float-box" style="top: {{top}}; left: {{left}};" bindtouchmove="viewTouchMove">
+  <slot wx:if="{{useSlot}}" />
+  <image wx:else style="width: 160rpx; height: 160rpx; transform: translate(-50%,-50%);" src='../../static/image/add.png' data-title="新建线索" />
+</view>

+ 66 - 0
components/Yl_FunTabs/index.js

@@ -0,0 +1,66 @@
+Component({
+    options: {
+        multipleSlots: true
+    },
+    properties: {
+        list: Array,
+        active: {
+            type: Number,
+            value: 0
+        },
+        onChenge: Function
+    },
+    data: {
+        scrollLeft: 0,
+        startPoint: 0, //记录滑动的初始位置
+        slipFlag: false, //定义 滑动事件 节流阀, 防止一次滑动触发多次滑动事件
+    },
+    methods: {
+        tabsChenge(e) {
+            const {
+                index
+            } = e.currentTarget.dataset;
+            if (this.data.active == index) return;
+            this.setData({
+                active: index
+            });
+            this.setActive();
+        },
+        setActive() {
+            const that = this,
+                active = this.data.active,
+                query = wx.createSelectorQuery().in(this)
+            query.select('#active' + active).boundingClientRect(function (res) {
+                that.setData({
+                    scrollLeft: res.right - res.width
+                })
+            }).exec();
+            this.triggerEvent("onChenge", active)
+        },
+        myTouchStart(e) {
+            return;
+            this.setData({
+                slipFlag: true,
+                startPoint: e.touches[0]
+            })
+        },
+        myTouchMove(e) {
+            return;
+            let active = this.data.active;
+            if (((this.data.startPoint.clientX - e.touches[e.touches.length - 1].clientX) > 80) && this.data.slipFlag) {
+                if (active != this.data.list.length - 1) active++;
+                this.setData({
+                    slipFlag: false,
+                    active
+                })
+            } else if (((this.data.startPoint.clientX - e.touches[e.touches.length - 1].clientX) < -80) && this.data.slipFlag) {
+                if (active != 0) active--;
+                this.setData({
+                    slipFlag: false,
+                    active
+                })
+            }
+            this.setActive();
+        },
+    }
+})

+ 6 - 0
components/Yl_FunTabs/index.json

@@ -0,0 +1,6 @@
+{
+    "component": true,
+    "usingComponents": {
+        "van-sticky": "@vant/weapp/sticky/index"
+    }
+}

+ 12 - 0
components/Yl_FunTabs/index.wxml

@@ -0,0 +1,12 @@
+<scroll-view scroll-x enable-flex class="scroll" scroll-left='{{scrollLeft}}' scroll-with-animation enable-passive>
+    <view class="item {{active==index?'active':''}}" id="{{active==index?'active'+index:''}}" wx:for="{{list}}" wx:key="index" data-index="{{index}}" bindtap="tabsChenge">
+        <view class="icon" wx:if="{{item.icon}}"></view>
+        <view wx:else class="num line-1">{{item.num}}</view>
+        <view class="label line-1">{{item.label}}</view>
+    </view>
+</scroll-view>
+<view class="slot-box" bindtouchstart="myTouchStart" bindtouchmove="myTouchMove">
+    <slot name='padtop' />
+    <slot name='{{list[active].label}}' />
+    <slot />
+</view>

+ 67 - 0
components/Yl_FunTabs/index.wxss

@@ -0,0 +1,67 @@
+.scroll {
+    position: sticky;
+    top: 0;
+    display: flex;
+    flex-wrap: nowrap;
+    width: 100vw;
+    height: 120rpx;
+    background-color: #ffffff;
+    z-index: 9;
+    box-shadow: rgba(0, 0, 0, 0.1) 0px 2px 8rpx;
+}
+
+.scroll .item {
+    flex-shrink: 0;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    height: 100%;
+    width: 172rpx;
+    padding-top: 16rpx;
+    text-align: center;
+    box-sizing: border-box;
+}
+
+.scroll .item .icon {
+    width: 46rpx;
+    height: 46rpx;
+    border: 1px solid red;
+}
+
+.scroll .item .num {
+    width: 80%;
+    height: 46rpx;
+    font-size: 28rpx;
+    font-family: PingFang SC-Bold, PingFang SC;
+    font-weight: bold;
+    color: #333333;
+}
+
+.scroll .item .label {
+    height: 34rpx;
+    font-size: 24rpx;
+    font-family: PingFang SC-Regular, PingFang SC;
+    color: #999999;
+    margin-top: 8rpx;
+}
+
+.scroll .active {
+    border-bottom: 4rpx solid #3874F6;
+}
+
+.scroll .active .label,
+.scroll .active .num,
+.scroll .active .icon {
+    color: #3874F6 !important;
+}
+
+.slot-box {
+    width: 100vw;
+    min-height: 200rpx;
+}
+
+.line-1 {
+    overflow: hidden;
+    white-space: nowrap;
+    text-overflow: ellipsis;
+}

+ 201 - 0
components/Yl_HeadNav/index.js

@@ -0,0 +1,201 @@
+const getHeight = require("../../utils/getRheRemainingHeight");
+Component({
+    options: {
+        addGlobalClass: true
+    },
+    properties: {
+        sort: Array, //排序规则列表
+        search: Boolean, //是否开启搜索
+        list: Array, //功能列表
+        condition: String, //搜索内容
+        onClick: Function,
+        startUsing: Boolean, //启用搜索
+        onSearch: Function, //搜索回调
+        record: { //记录历史
+            type: Boolean,
+            value: true
+        }
+    },
+    data: {
+        sortShow: false,
+        reversed: 0, //是否翻转
+        condition: "",
+        history: [], //搜索历史
+        showHistory: false,
+        listHeight: null,
+    },
+    lifetimes: {
+        attached() {
+            if (wx.getStorageSync('SearchHistory')) this.setData({
+                history: wx.getStorageSync('SearchHistory')
+            })
+        },
+        ready() {
+            getHeight.getHeight('.Yl_head', this).then(res => this.setData({
+                listHeight: res - 200
+            }));
+        }
+    },
+    methods: {
+        /* 排序 */
+        sortClick(e) {
+            const {
+                name
+            } = e.target.dataset;
+            if (name == 'confirm') {
+                let sort = this.data.sort.find(v => v.sorted == 1),
+                    i = this.data.list.findIndex(v => v.id == 'sort');
+                this.setData({
+                    [`list[${i}].label`]: sort.sortname,
+                    [`list[${i}].icon`]: sort.reversed == 1 ? 'icon-jiangxu1' : 'icon-shengxu',
+                })
+                let pages = getCurrentPages(),
+                    page = pages[pages.length - 1];
+                page.setData({
+                    "content.sort": this.data.sort
+                });
+                page.getList(true);
+            };
+            this.setData({
+                sortShow: false
+            })
+        },
+        sortClose() {
+            this.setData({
+                sortShow: false
+            })
+        },
+        /* 设置排序规则 */
+        handleSort(e) {
+            const {
+                id
+            } = e.currentTarget.dataset;
+            this.setData({
+                sort: this.data.sort.map(v => {
+                    v.sorted = v.sortid == id ? 1 : 0
+                    return v;
+                })
+            });
+        },
+        /* 设置升序和倒叙 */
+        handleReversed(e) {
+            let {
+                id
+            } = e.currentTarget.dataset;
+            if (this.data.reversed == id) return;
+            this.setData({
+                reversed: id,
+                sort: this.data.sort.map(v => {
+                    v.reversed = id;
+                    return v;
+                })
+            });
+        },
+        onClick(e) {
+            const {
+                item
+            } = e.currentTarget.dataset;
+            if (item.id == "sort") {
+                //排序
+                this.setData({
+                    sortShow: true
+                })
+            } else {
+                this.triggerEvent("onClick", item)
+            }
+        },
+        /* 开启关闭搜索 */
+        clickSearch() {
+            this.setData({
+                startUsing: !this.data.startUsing
+            });
+            setTimeout(this.setListHeight, 400)
+        },
+        /* 开始搜索 */
+        startSearch({
+            detail
+        }) {
+            if (this.data.condition == detail) return;
+            this.setData({
+                condition: detail
+            })
+            this.triggerEvent("onSearch", detail)
+            if (this.data.record || detail == '') {
+                let list = this.data.history;
+                if (list.findIndex(v => v == detail) == -1) {
+                    list.push(detail)
+                    this.setData({
+                        history: list
+                    });
+                    wx.setStorageSync("SearchHistory", list)
+                }
+            }
+        },
+        /* 取消搜索 */
+        endSearch() {
+            this.setData({
+                condition: ""
+            })
+            this.triggerEvent("onSearch", "")
+        },
+        /* 删除搜索历史 */
+        deleteHistory(e) {
+            let that = this;
+            wx.showModal({
+                title: '提示',
+                content: '是否删除所有搜索历史',
+                complete: ({
+                    confirm
+                }) => {
+                    if (confirm) {
+                        wx.setStorageSync("SearchHistory", [])
+                        that.setData({
+                            history: []
+                        });
+                        this.setListHeight();
+                    }
+                }
+            })
+        },
+        /* 快速搜索 */
+        clickTag(e) {
+            const {
+                name
+            } = e.currentTarget.dataset;
+            this.setData({
+                condition: name
+            });
+            this.triggerEvent("onSearch", name)
+        },
+        /* 单独删除 */
+        delteTag(e) {
+            const {
+                name
+            } = e.currentTarget.dataset;
+            this.setData({
+                history: this.data.history.filter(v => v != name)
+            });
+            wx.setStorageSync('SearchHistory', this.data.history);
+            this.setListHeight();
+        },
+        /* 设置列表高度 */
+        setListHeight() {
+            let pages = getCurrentPages();
+            if (pages[pages.length - 1].setListHeight) pages[pages.length - 1].setListHeight();
+        },
+        /* 搜索框焦点 */
+        onFocus() {
+            this.setData({
+                showHistory: true
+            });
+            setTimeout(this.setListHeight, 50);
+        },
+        /* 搜索框失焦 */
+        onBlur() {
+            this.setData({
+                showHistory: false
+            })
+            setTimeout(this.setListHeight, 50);
+        }
+    }
+})

+ 6 - 0
components/Yl_HeadNav/index.json

@@ -0,0 +1,6 @@
+{
+    "component": true,
+    "usingComponents": {
+        "van-transition": "@vant/weapp/transition/index"
+    }
+}

+ 89 - 0
components/Yl_HeadNav/index.scss

@@ -0,0 +1,89 @@
+@import "../Yl_filtrate/index.scss";
+@import "../Yl_filtrate/groud.scss";
+
+.Yl_nav_box {
+    display: flex;
+    width: 100vw;
+    height: 90rpx;
+    background-color: #fff;
+    position: sticky;
+    top: 0;
+    border-bottom: 1px solid #ddd;
+
+    .mian {
+        flex: 1;
+        display: flex;
+        justify-content: space-around;
+
+        .item {
+            width: 216rpx;
+            height: 90rpx;
+            line-height: 90rpx;
+            text-align: center;
+            font-size: 28rpx;
+            font-family: PingFang SC-Regular, PingFang SC;
+            color: #666666;
+
+            .iconfont {
+                font-size: 28rpx;
+                margin-right: 4rpx;
+            }
+        }
+    }
+
+    .search {
+        width: 90rpx;
+        height: 90rpx;
+        line-height: 90rpx;
+        text-align: center;
+        flex-shrink: 0;
+    }
+}
+
+.Yl_search {
+    height: 80rpx !important;
+    align-items: flex-start;
+}
+
+.Yl_history {
+    width: 100vw;
+    background-color: #fff;
+    box-sizing: border-box;
+    padding: 6rpx 30rpx 15rpx;
+
+    .label {
+        display: flex;
+        justify-content: space-between;
+        height: 50rpx;
+        line-height: 58rpx;
+        font-size: 24rpx;
+        font-family: PingFang SC-Regular, PingFang SC;
+        color: #666666;
+
+        .iconfont {
+            display: inline-block;
+            width: 80rpx;
+            text-align: center;
+            margin-right: -30rpx;
+        }
+    }
+}
+
+.content .iconfont {
+    color: rgb(63, 62, 62);
+    margin-right: 8rpx;
+}
+
+.active .iconfont {
+    color: #3874F6 !important;
+}
+
+.footer {
+    align-items: center !important;
+    box-sizing: border-box;
+    padding-left: 30rpx;
+    padding-right: 30rpx;
+    .v-but {
+        width: 250rpx !important;
+    }
+}

+ 54 - 0
components/Yl_HeadNav/index.wxml

@@ -0,0 +1,54 @@
+<view class="Yl_nav_box">
+    <view class="mian">
+        <navigator class="item" url="#" wx:for="{{list}}" wx:key="index" style="width: {{item.width}};" bindtap="onClick" data-item="{{item}}">
+            <text class="iconfont {{item.icon}}" style="color: {{item.color}};" />
+            <text class="label">{{item.label}}</text>
+        </navigator>
+    </view>
+    <navigator wx:if="{{search}}" class="search" url="#" bindtap="clickSearch">
+        <text class="iconfont icon-a-sousuolansousuo" style="color: {{startUsing?'var(--assist)':''}};" />
+    </navigator>
+</view>
+
+<van-transition show="{{ startUsing }}" custom-class="block">
+    <van-search custom-class='Yl_search' value="{{ condition }}" bindfocus='onFocus' bind:blur='onBlur' shape="round" placeholder="请输入搜索关键词" bind:search='startSearch' bind:clear='endSearch' />
+    <view class="Yl_history" wx:if="{{record}}">
+        <view class="label" wx:if="{{showHistory && history.length}}">
+            <text>最近搜索记录</text>
+            <!-- <text class="iconfont icon-guanlian-shanchu" style="font-size: 24rpx;" bindtap="deleteHistory" /> -->
+        </view>
+        <view class="content" wx:if="{{showHistory}}">
+            <!-- closeable -->
+            <van-tag wx:for="{{history}}" style="margin-left: 6rpx;" wx:key="item" size="medium" round data-name="{{item}}" catch:close="delteTag" catchtap="clickTag">
+                {{item}}
+            </van-tag>
+        </view>
+    </view>
+</van-transition>
+
+<van-popup show="{{ sortShow }}" position="right" custom-style="width: 660rpx; height:100vh;overflow: hidden;" safe-area-inset-bottom='{{false}}' bind:close="sortClose">
+    <view class="Yl_head" />
+    <My_listBox height="{{listHeight}}" pullDown='{{false}}'>
+        <view class="groud" wx:if="{{filter.stageList.length!=0}}">
+            <view class="label">
+                排序类型
+            </view>
+            <view class="content">
+                <van-button custom-class='but {{item.sorted==1?"active":""}}' wx:for="{{sort}}" wx:key="item.sortid" bindtap="handleSort" data-id="{{item.sortid}}">{{item.sortname}}</van-button>
+            </view>
+        </view>
+        <view class="groud" wx:if="{{filter.stageList.length!=0}}">
+            <view class="label">
+                查看顺序
+            </view>
+            <view class="content">
+                <van-button custom-class='but {{reversed==0?"active":""}}' bindtap="handleReversed" data-id="0"><text class="iconfont icon-jiangxu1" />降序</van-button>
+                <van-button custom-class='but {{reversed==1?"active":""}}' bindtap="handleReversed" data-id="1"><text class="iconfont icon-shengxu" />升序</van-button>
+            </view>
+        </view>
+    </My_listBox>
+    <view class="footer" bindtap="sortClick">
+        <van-button data-name="close" custom-class='v-but'>关闭</van-button>
+        <van-button data-name="confirm" custom-class='v-but confirm'>确定</van-button>
+    </view>
+</van-popup>

+ 56 - 0
components/Yl_ListBox/index.js

@@ -0,0 +1,56 @@
+// components/My_listBox/index.js
+
+Component({
+    /**
+     * 组件的属性列表
+     */
+    properties: {
+        height: {
+            type: Number,
+            value: 0
+        },
+        getlist: {
+            type: Function
+        },
+        pullDown: {
+            type: Boolean,
+            value: true
+        }
+    },
+
+    lifetimes: {
+        ready() {}
+    },
+
+    /**
+     * 组件的初始数据
+     */
+    data: {
+        inRefresh: false
+    },
+
+    /**
+     * 组件的方法列表
+     */
+    methods: {
+        /* 下拉刷新 */
+        pullToRefresh() {
+            this.setData({
+                inRefresh: true
+            })
+            this.triggerEvent("getlist", true)
+        },
+        /* 刷新完成 */
+        RefreshToComplete() {
+            setTimeout(() => {
+                this.setData({
+                    inRefresh: false
+                })
+            }, 500)
+        },
+        /* 加载分页 */
+        loadThePage() {
+            this.triggerEvent("getlist", false)
+        },
+    }
+})

+ 4 - 0
components/Yl_ListBox/index.json

@@ -0,0 +1,4 @@
+{
+    "component": true,
+    "usingComponents": {}
+}

+ 4 - 0
components/Yl_ListBox/index.scss

@@ -0,0 +1,4 @@
+/* components/My_listBox/index.wxss */
+.scroll-view{
+    position: relative;
+}

+ 3 - 0
components/Yl_ListBox/index.wxml

@@ -0,0 +1,3 @@
+<scroll-view class="scroll-view" scroll-y refresher-enabled='{{pullDown}}' refresher-triggered='{{inRefresh}}' style="height: {{height}}rpx;" triggered='{{true}}' bindrefresherrefresh='pullToRefresh' bindscrolltolower='loadThePage'>
+    <slot />
+</scroll-view>

+ 65 - 0
components/Yl_Tabbar/index.js

@@ -0,0 +1,65 @@
+Component({
+    properties: {
+        list: Array,
+        callback: Function
+    },
+    data: {
+        safeAreaBot: 0,
+        show: false,
+        showList: [],
+        extend: []
+    },
+    lifetimes: {
+        attached: function () {
+            wx.getSystemInfo({
+                success: res => {
+                    this.setData({
+                        safeAreaBot: res.screenHeight - res.safeArea.bottom
+                    })
+                }
+            })
+        },
+    },
+    observers: {
+        'list': function (numberA, numberB) {
+            if (numberA.length >= 5) {
+                let showList = numberA.splice(0, 3);
+                showList.push({
+                    icon: "icon-gengduo",
+                    label: "更多"
+                })
+                this.setData({
+                    showList,
+                    extend: numberA
+                })
+            } else {
+                this.setData({
+                    showList: numberA
+                })
+            }
+        }
+    },
+    options: {
+        addGlobalClass: true
+    },
+    methods: {
+        onClose() {
+            this.setData({
+                show: false
+            })
+        },
+        callback(e) {
+            const {
+                item
+            } = e.currentTarget.dataset;
+            if (item.label == '更多') return this.setData({
+                show: true
+            })
+            if (this.data.show) this.setData({
+                show: false
+            })
+            if (!item) return;
+            this.triggerEvent("callback", item)
+        }
+    }
+})

+ 6 - 0
components/Yl_Tabbar/index.json

@@ -0,0 +1,6 @@
+{
+  "component": true,
+  "usingComponents": {
+    "van-popup": "@vant/weapp/popup/index"
+  }
+}

+ 21 - 0
components/Yl_Tabbar/index.wxml

@@ -0,0 +1,21 @@
+<view class="tabbar" style="padding-bottom: {{safeAreaBot}}rpx;">
+    <navigator url="#" class="tabbar-item" wx:for="{{showList}}" wx:key="index" data-item="{{item}}" bindtap="callback">
+        <view class="icon" wx:if="{{item.icon}}">
+            <text class="iconfont {{item.icon}}" />
+        </view>
+        <view wx:else class="num line-1">{{item.num}}</view>
+        <view class="label line-1">{{item.label}}</view>
+    </navigator>
+</view>
+<van-popup show="{{ show }}" position="bottom" bind:close="onClose" round>
+    <view class="extend">
+        <navigator url="#" class="tabbar-item" wx:for="{{extend}}" wx:key="index" data-item="{{item}}" bindtap="callback">
+            <view class="icon" wx:if="{{item.icon}}">
+                <text class="iconfont {{item.icon}}" />
+            </view>
+            <view wx:else class="num line-1">{{item.num}}</view>
+            <view class="label line-1">{{item.label}}</view>
+        </navigator>
+    </view>
+    <view style="height: 110rpx;" />
+</van-popup>

+ 80 - 0
components/Yl_Tabbar/index.wxss

@@ -0,0 +1,80 @@
+.tabbar {
+    display: flex;
+    justify-content: space-around;
+    position: fixed;
+    height: 110rpx;
+    width: 100vw;
+    bottom: 0;
+    background-color: #fff;
+    z-index: 999;
+    box-shadow: rgba(0, 0, 0, 0.1) 0px -2px 8rpx;
+}
+
+/* 更多 */
+.extend {
+    display: flex;
+    padding-top: 30rpx;
+    flex-wrap: wrap;
+}
+
+.extend .tabbar-item {
+    flex: none;
+    width: 25%;
+    margin-bottom: 10rpx;
+}
+
+.tabbar-item {
+    flex: 1;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    height: 98rpx;
+}
+
+.tabbar-item .icon {
+    width: 46rpx;
+    height: 46rpx;
+    text-align: center;
+    line-height: 46rpx;
+    color: #333333;
+}
+
+.tabbar-item .num {
+    width: 80%;
+    height: 46rpx;
+    font-size: 28rpx;
+    font-family: PingFang SC-Bold, PingFang SC;
+    font-weight: bold;
+    color: #333333;
+}
+
+.tabbar-item .label {
+    height: 34rpx;
+    font-size: 24rpx;
+    font-family: PingFang SC-Regular, PingFang SC;
+    color: #999999;
+    margin-top: 8rpx;
+}
+
+.title {
+    width: 100vw;
+    height: 90rpx;
+    line-height: 90rpx;
+    text-align: center;
+    box-sizing: border-box;
+    border-bottom: 1px solid #EEEEEE;
+    font-size: 28rpx;
+    font-family: PingFang SC-Regular, PingFang SC;
+    color: #333333;
+}
+
+swiper-item {
+    display: flex;
+    flex-wrap: wrap;
+    align-content: flex-start;
+}
+
+.swiper-item {
+    width: 150rpx;
+    height: 150rpx;
+}

+ 29 - 0
pages/home/index.js

@@ -0,0 +1,29 @@
+Page({
+  data: {
+
+  },
+  onLoad(options) {
+
+  },
+  onReady() {
+
+  },
+  onShow() {
+
+  },
+  onHide() {
+
+  },
+  onUnload() {
+
+  },
+  onPullDownRefresh() {
+
+  },
+  onReachBottom() {
+
+  },
+  onShareAppMessage() {
+
+  }
+})

+ 3 - 0
pages/home/index.json

@@ -0,0 +1,3 @@
+{
+  "usingComponents": {}
+}

+ 0 - 0
pages/home/index.scss


+ 0 - 0
pages/home/index.wxml


+ 4 - 1
project.config.json

@@ -37,7 +37,10 @@
       "disablePlugins": [],
       "outputPath": ""
     },
-    "ignoreUploadUnusedFiles": true
+    "ignoreUploadUnusedFiles": true,
+    "useCompilerPlugins": [
+      "sass"
+    ]
   },
   "compileType": "miniprogram",
   "condition": {},

+ 63 - 0
utils/Api.js

@@ -0,0 +1,63 @@
+import {
+    HTTP
+} from './Http.js'
+class ApiModel extends HTTP {
+    loginbywechat(data) {
+        return this.request({
+            url: "/loginbywechat",
+            data
+        })
+    }
+    /* 登录 */
+    login(data) {
+        return this.request({
+            url: "/loginbyaccount",
+            data
+        })
+    }
+    /* 验证码登录 */
+    plogin(data) {
+        return this.request({
+            url: "/login",
+            data
+        })
+    }
+    /* 获取验证码 */
+    getpassword(data) {
+        return this.request({
+            url: "/getpassword",
+            data
+        })
+    }
+    /* 有状态通用 */
+    basic(data, loading = true) {
+        data.accesstoken = wx.getStorageSync('userMsg').token;
+        return this.request({
+            url: "",
+            data,
+            loading
+        })
+    }
+    /* 无状态 */
+    base(data, loading = true) {
+        return this.request({
+            url: "",
+            data,
+            loading
+        })
+    }
+    /* 退出登录 */
+    logout() {
+        let data = {
+            accesstoken: wx.getStorageSync('userMsg').token
+        }
+        return this.request({
+            url: "/logout",
+            data
+        })
+    }
+
+}
+export {
+    ApiModel
+}

+ 34 - 0
utils/Check.js

@@ -0,0 +1,34 @@
+/* 去除字符串中的特殊符号 */
+const queryStr = (str) => {
+    const pattern = new RegExp(/[`$%^&()\=<>"{}|\/;'\\[\]·¥%……&——\={}|]/g);
+    if (pattern.test(str) == true) wx.showToast({
+        title: '该符号不可输入!',
+        icon: "none"
+    })
+    return str.replace(pattern, '');
+}
+/* 校验手机号码 */
+const CheckPhoneNumber = (num) => {
+    const reg = /^1(3[0-9]|4[01456879]|5[0-35-9]|6[2567]|7[0-8]|8[0-9]|9[0-35-9])\d{8}$/;
+    let isAllow = reg.test(num);
+    if (!isAllow) wx.showToast({
+        title: '请输入正确的11位手机号码!',
+        icon: "none"
+    })
+    return isAllow;
+}
+/* 校验邮箱 */
+const CheckEmail = (num) => {
+    const reg = /^([A-Za-z0-9_\-\.])+\@([A-Za-z0-9_\-\.])+\.([A-Za-z]{2,4})$/;
+    let isAllow = reg.test(num);
+    if (!isAllow) wx.showToast({
+        title: '请输入正确的邮箱格式!',
+        icon: "none"
+    })
+    return isAllow;
+}
+module.exports = {
+    queryStr,
+    CheckPhoneNumber,
+    CheckEmail
+}

+ 53 - 0
utils/CheckFile.js

@@ -0,0 +1,53 @@
+module.exports.checkFile = (item) => {
+    if (['image', 'video'].includes(item.fileType)) {
+        preViewMedia(item)
+    } else if (['word', 'excel', 'ppt', 'pdf'].includes(item.fileType)) {
+        openDocument(item)
+    } else {
+        wx.setClipboardData({
+            data: item.url,
+            success: function () {
+                wx.showToast({
+                    title: '当前文件类型不支持在线浏览,已将文件下载地址复制到剪切板,您可在浏览器中打开链接下载到本地浏览',
+                    icon: "none",
+                    duration: 5000
+                });
+            }
+        })
+    }
+}
+
+function preViewMedia(item) {
+    wx.previewMedia({
+        sources: [{
+            url: item.url,
+            type: item.fileType,
+        }],
+        current: 0,
+        showmenu: true
+    })
+}
+
+function openDocument(item) {
+    wx.downloadFile({
+        url: item.url,
+        success: function (res) {
+            console.log(res.tempFilePath)
+            wx.openDocument({
+                filePath: res.tempFilePath,
+                fileType: item.postfix,
+                showMenu: true,
+                success: function (res) {
+                    console.log(res)
+                    console.log('打开文档成功')
+                },
+                fail: (err) => {
+                    wx.showToast({
+                        title: '打开失败',
+                        icon: "none"
+                    })
+                }
+            })
+        }
+    })
+}

+ 48 - 0
utils/FormatTheAttachment.js

@@ -0,0 +1,48 @@
+function fileList(list) {
+    let suffixList = {
+            image: ['png', 'jpg', 'jpeg', 'bmp', 'gif', 'webp', 'svg', 'tiff'],
+            video: ['mp4', 'ogg', 'webm'],
+            word: ['doc', 'docx'],
+            excel: ['xls', 'xlsx'],
+            ppt: ['ppt', 'pptx'],
+            txt: ['txt', 'md', 'js', 'json'],
+            pdf: ['pdf'],
+            rar: ['7z', 'zip', 'rar', 'kz', 'ace', 'arj', 'bz2', 'cab', 'gz', 'iso', 'jar', 'lzh', 'tar', 'z'],
+            folder: ['"folder"']
+        },
+        typeList = [];
+    for (let key in suffixList) typeList.push(key);
+    for (let i = 0; i < list.length; i++) {
+        list[i].fileType = 'unknown';
+        list[i].cover = `/static/image/file/unknown.png`
+        const suffix = list[i].postfix.toLowerCase();
+        if (suffix != "folder") {
+            for (var key in suffixList) {
+                if (suffixList[key].some(value => value == suffix)) {
+                    list[i].fileType = key;
+                    if (key == 'image') {
+                        list[i].cover = list[i].url;
+                    } else if (typeList.includes(key)) {
+                        list[i].cover = `/static/image/file/${key}.png`;
+                    }
+                }
+            }
+        } else {
+            list[i].fileType = "folder";
+            list[i].cover = `/static/image/file/folder.png`
+        }
+    }
+    return list;
+};
+
+//得到缩略图或者压缩图  getType默认得到缩略图传true得到压缩图
+function getSpecifiedImage(obj, getType = false) {
+    let type = getType ? 'compressed' : 'thumbnail';
+    let imgObj = obj.subfiles.find(v => v.type == type);
+    return imgObj.url;
+}
+
+module.exports = {
+    fileList,
+    getSpecifiedImage
+}

+ 13 - 0
utils/GetRheRemainingHeight.js

@@ -0,0 +1,13 @@
+ function getHeight(even, that) {
+     return new Promise((resolve, reject) => {
+         let windowHeight = 0;
+         wx.getSystemInfo({
+             success: (res => windowHeight = res.windowHeight)
+         });
+         let query = wx.createSelectorQuery().in(that).select(even).boundingClientRect();
+         query.exec(res => (!res[0]) ? reject('没有查询到元素') : resolve((windowHeight - res[0].bottom) * 2))
+     })
+ }
+ module.exports = {
+     getHeight
+ }

+ 62 - 0
utils/Http.js

@@ -0,0 +1,62 @@
+// const baseUrl = "https://meida.cnyunl.com/yos/rest/index";
+const baseUrl = "http://61.164.207.46:8000/yos/rest/index";
+let count = null;
+class HTTP {
+    request({
+        url,
+        data = {},
+        method = "POST",
+        header = {
+            'content-type': 'application/json'
+        },
+        loading = true
+    }) {
+        return new Promise((resolve, reject) => {
+            this._request(url, resolve, reject, data, method, header, loading);
+        })
+    }
+    _request(url, resolve, reject, data, method, header, loading) {
+        if (loading) wx.showLoading({
+            title: '加载中...',
+            mask: true
+        })
+        wx.request({
+            url: baseUrl + url,
+            data: data,
+            method: method,
+            header: header,
+            timeout: 60000,
+            success: (res) => {
+                resolve(res.data);
+                if (loading) wx.hideLoading();
+            },
+            fial: (err) => {
+                reject(err);
+                if (loading) wx.hideLoading()
+            },
+            complete: (res) => {
+                if (res.errMsg != 'request:ok') {
+                    wx.hideLoading()
+                    wx.showToast({
+                        title: '网络异常,请重新进入',
+                        icon: "none"
+                    })
+                } else if (res.data.msg == '登陆状态已过期,请重新登陆!') {
+                    clearTimeout(count);
+                    wx.showToast({
+                        title: '登陆状态已过期,请重新登陆!',
+                        icon: "none"
+                    })
+                    count = setTimeout(() => {
+                        wx.redirectTo({
+                            url: '/pages/login/phone',
+                        });
+                    }, 500)
+                }
+            }
+        })
+    }
+}
+export {
+    HTTP
+}

+ 223 - 0
utils/md5.js

@@ -0,0 +1,223 @@
+/* 
+ * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message 
+ * Digest Algorithm, as defined in RFC 1321. 
+ * Version 1.1 Copyright (C) Paul Johnston 1999 - 2002. 
+ * Code also contributed by Greg Holt 
+ * See http://pajhome.org.uk/site/legal.html for details. 
+ */
+
+/* 
+ * Add integers, wrapping at 2^32. This uses 16-bit operations internally 
+ * to work around bugs in some JS interpreters. 
+ */
+function safe_add(x, y) {
+    var lsw = (x & 0xFFFF) + (y & 0xFFFF)
+    var msw = (x >> 16) + (y >> 16) + (lsw >> 16)
+    return (msw << 16) | (lsw & 0xFFFF)
+}
+
+/* 
+ * Bitwise rotate a 32-bit number to the left. 
+ */
+function rol(num, cnt) {
+    return (num << cnt) | (num >>> (32 - cnt))
+}
+
+/* 
+ * These functions implement the four basic operations the algorithm uses. 
+ */
+function cmn(q, a, b, x, s, t) {
+    return safe_add(rol(safe_add(safe_add(a, q), safe_add(x, t)), s), b)
+}
+
+function ff(a, b, c, d, x, s, t) {
+    return cmn((b & c) | ((~b) & d), a, b, x, s, t)
+}
+
+function gg(a, b, c, d, x, s, t) {
+    return cmn((b & d) | (c & (~d)), a, b, x, s, t)
+}
+
+function hh(a, b, c, d, x, s, t) {
+    return cmn(b ^ c ^ d, a, b, x, s, t)
+}
+
+function ii(a, b, c, d, x, s, t) {
+    return cmn(c ^ (b | (~d)), a, b, x, s, t)
+}
+
+/* 
+ * Calculate the MD5 of an array of little-endian words, producing an array 
+ * of little-endian words. 
+ */
+function coreMD5(x) {
+    var a = 1732584193
+    var b = -271733879
+    var c = -1732584194
+    var d = 271733878
+
+    for (var i = 0; i < x.length; i += 16) {
+        var olda = a
+        var oldb = b
+        var oldc = c
+        var oldd = d
+
+        a = ff(a, b, c, d, x[i + 0], 7, -680876936)
+        d = ff(d, a, b, c, x[i + 1], 12, -389564586)
+        c = ff(c, d, a, b, x[i + 2], 17, 606105819)
+        b = ff(b, c, d, a, x[i + 3], 22, -1044525330)
+        a = ff(a, b, c, d, x[i + 4], 7, -176418897)
+        d = ff(d, a, b, c, x[i + 5], 12, 1200080426)
+        c = ff(c, d, a, b, x[i + 6], 17, -1473231341)
+        b = ff(b, c, d, a, x[i + 7], 22, -45705983)
+        a = ff(a, b, c, d, x[i + 8], 7, 1770035416)
+        d = ff(d, a, b, c, x[i + 9], 12, -1958414417)
+        c = ff(c, d, a, b, x[i + 10], 17, -42063)
+        b = ff(b, c, d, a, x[i + 11], 22, -1990404162)
+        a = ff(a, b, c, d, x[i + 12], 7, 1804603682)
+        d = ff(d, a, b, c, x[i + 13], 12, -40341101)
+        c = ff(c, d, a, b, x[i + 14], 17, -1502002290)
+        b = ff(b, c, d, a, x[i + 15], 22, 1236535329)
+
+        a = gg(a, b, c, d, x[i + 1], 5, -165796510)
+        d = gg(d, a, b, c, x[i + 6], 9, -1069501632)
+        c = gg(c, d, a, b, x[i + 11], 14, 643717713)
+        b = gg(b, c, d, a, x[i + 0], 20, -373897302)
+        a = gg(a, b, c, d, x[i + 5], 5, -701558691)
+        d = gg(d, a, b, c, x[i + 10], 9, 38016083)
+        c = gg(c, d, a, b, x[i + 15], 14, -660478335)
+        b = gg(b, c, d, a, x[i + 4], 20, -405537848)
+        a = gg(a, b, c, d, x[i + 9], 5, 568446438)
+        d = gg(d, a, b, c, x[i + 14], 9, -1019803690)
+        c = gg(c, d, a, b, x[i + 3], 14, -187363961)
+        b = gg(b, c, d, a, x[i + 8], 20, 1163531501)
+        a = gg(a, b, c, d, x[i + 13], 5, -1444681467)
+        d = gg(d, a, b, c, x[i + 2], 9, -51403784)
+        c = gg(c, d, a, b, x[i + 7], 14, 1735328473)
+        b = gg(b, c, d, a, x[i + 12], 20, -1926607734)
+
+        a = hh(a, b, c, d, x[i + 5], 4, -378558)
+        d = hh(d, a, b, c, x[i + 8], 11, -2022574463)
+        c = hh(c, d, a, b, x[i + 11], 16, 1839030562)
+        b = hh(b, c, d, a, x[i + 14], 23, -35309556)
+        a = hh(a, b, c, d, x[i + 1], 4, -1530992060)
+        d = hh(d, a, b, c, x[i + 4], 11, 1272893353)
+        c = hh(c, d, a, b, x[i + 7], 16, -155497632)
+        b = hh(b, c, d, a, x[i + 10], 23, -1094730640)
+        a = hh(a, b, c, d, x[i + 13], 4, 681279174)
+        d = hh(d, a, b, c, x[i + 0], 11, -358537222)
+        c = hh(c, d, a, b, x[i + 3], 16, -722521979)
+        b = hh(b, c, d, a, x[i + 6], 23, 76029189)
+        a = hh(a, b, c, d, x[i + 9], 4, -640364487)
+        d = hh(d, a, b, c, x[i + 12], 11, -421815835)
+        c = hh(c, d, a, b, x[i + 15], 16, 530742520)
+        b = hh(b, c, d, a, x[i + 2], 23, -995338651)
+
+        a = ii(a, b, c, d, x[i + 0], 6, -198630844)
+        d = ii(d, a, b, c, x[i + 7], 10, 1126891415)
+        c = ii(c, d, a, b, x[i + 14], 15, -1416354905)
+        b = ii(b, c, d, a, x[i + 5], 21, -57434055)
+        a = ii(a, b, c, d, x[i + 12], 6, 1700485571)
+        d = ii(d, a, b, c, x[i + 3], 10, -1894986606)
+        c = ii(c, d, a, b, x[i + 10], 15, -1051523)
+        b = ii(b, c, d, a, x[i + 1], 21, -2054922799)
+        a = ii(a, b, c, d, x[i + 8], 6, 1873313359)
+        d = ii(d, a, b, c, x[i + 15], 10, -30611744)
+        c = ii(c, d, a, b, x[i + 6], 15, -1560198380)
+        b = ii(b, c, d, a, x[i + 13], 21, 1309151649)
+        a = ii(a, b, c, d, x[i + 4], 6, -145523070)
+        d = ii(d, a, b, c, x[i + 11], 10, -1120210379)
+        c = ii(c, d, a, b, x[i + 2], 15, 718787259)
+        b = ii(b, c, d, a, x[i + 9], 21, -343485551)
+
+        a = safe_add(a, olda)
+        b = safe_add(b, oldb)
+        c = safe_add(c, oldc)
+        d = safe_add(d, oldd)
+    }
+    return [a, b, c, d]
+}
+
+/* 
+ * Convert an array of little-endian words to a hex string. 
+ */
+function binl2hex(binarray) {
+    var hex_tab = "0123456789abcdef"
+    var str = ""
+    for (var i = 0; i < binarray.length * 4; i++) {
+        str += hex_tab.charAt((binarray[i >> 2] >> ((i % 4) * 8 + 4)) & 0xF) +
+            hex_tab.charAt((binarray[i >> 2] >> ((i % 4) * 8)) & 0xF)
+    }
+    return str
+}
+
+/* 
+ * Convert an array of little-endian words to a base64 encoded string. 
+ */
+function binl2b64(binarray) {
+    var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
+    var str = ""
+    for (var i = 0; i < binarray.length * 32; i += 6) {
+        str += tab.charAt(((binarray[i >> 5] << (i % 32)) & 0x3F) |
+            ((binarray[i >> 5 + 1] >> (32 - i % 32)) & 0x3F))
+    }
+    return str
+}
+
+/* 
+ * Convert an 8-bit character string to a sequence of 16-word blocks, stored 
+ * as an array, and append appropriate padding for MD4/5 calculation. 
+ * If any of the characters are >255, the high byte is silently ignored. 
+ */
+function str2binl(str) {
+    var nblk = ((str.length + 8) >> 6) + 1 // number of 16-word blocks  
+    var blks = new Array(nblk * 16)
+    for (var i = 0; i < nblk * 16; i++) blks[i] = 0
+    for (var i = 0; i < str.length; i++)
+        blks[i >> 2] |= (str.charCodeAt(i) & 0xFF) << ((i % 4) * 8)
+    blks[i >> 2] |= 0x80 << ((i % 4) * 8)
+    blks[nblk * 16 - 2] = str.length * 8
+    return blks
+}
+
+/* 
+ * Convert a wide-character string to a sequence of 16-word blocks, stored as 
+ * an array, and append appropriate padding for MD4/5 calculation. 
+ */
+function strw2binl(str) {
+    var nblk = ((str.length + 4) >> 5) + 1 // number of 16-word blocks  
+    var blks = new Array(nblk * 16)
+    for (var i = 0; i < nblk * 16; i++) blks[i] = 0
+    for (var i = 0; i < str.length; i++)
+        blks[i >> 1] |= str.charCodeAt(i) << ((i % 2) * 16)
+    blks[i >> 1] |= 0x80 << ((i % 2) * 16)
+    blks[nblk * 16 - 2] = str.length * 16
+    return blks
+}
+
+/* 
+ * External interface 
+ */
+function hexMD5(str) {
+    return binl2hex(coreMD5(str2binl(str)))
+}
+
+function hexMD5w(str) {
+    return binl2hex(coreMD5(strw2binl(str)))
+}
+
+function b64MD5(str) {
+    return binl2b64(coreMD5(str2binl(str)))
+}
+
+function b64MD5w(str) {
+    return binl2b64(coreMD5(strw2binl(str)))
+}
+/* Backward compatibility */
+function calcMD5(str) {
+    return binl2hex(coreMD5(str2binl(str)))
+}
+module.exports = {
+    hexMD5: hexMD5,
+    hexMD5w
+}