linwenxin 5 місяців тому
батько
коміт
b924a659ac
28 змінених файлів з 2371 додано та 0 видалено
  1. 145 0
      src/components/zj-container/zj-fiex-column.vue
  2. 144 0
      src/components/zj-container/zj-fiex-row.vue
  3. 25 0
      src/components/zj-container/zj-page-container.vue
  4. 206 0
      src/components/zj-upload/index.vue
  5. BIN
      src/components/zj-upload/loading.png
  6. 66 0
      src/packageEnter/components/zj-date.vue
  7. 48 0
      src/packageEnter/pages/insurance/detailsAgreement/index.vue
  8. 8 0
      src/packageEnter/pages/insurance/detailsAgreement/style.scss
  9. 142 0
      src/packageEnter/pages/insurance/determineInfo/index.vue
  10. 98 0
      src/packageEnter/pages/insurance/determineInfo/style.scss
  11. 95 0
      src/packageEnter/pages/insurance/insuranceContract/index.vue
  12. 39 0
      src/packageEnter/pages/insurance/insuranceContract/style.scss
  13. 219 0
      src/packageEnter/pages/insurance/insurancePolicy/index.vue
  14. 68 0
      src/packageEnter/pages/insurance/insurancePolicy/style.scss
  15. 84 0
      src/packageEnter/pages/insurance/myInsurance/index.vue
  16. 68 0
      src/packageEnter/pages/insurance/myInsuranceBuy/index.vue
  17. 208 0
      src/packageEnter/pages/insurance/policyParticulars/index.vue
  18. 118 0
      src/packageEnter/pages/insurance/policyParticulars/style.scss
  19. 52 0
      src/pages.json
  20. 6 0
      src/pages/mine/index.vue
  21. BIN
      src/static/images/common/bpa.png
  22. BIN
      src/static/images/common/dsx.png
  23. BIN
      src/static/images/common/qrcode.png
  24. BIN
      src/static/images/common/yshx.png
  25. BIN
      src/static/images/common/ysx.png
  26. 258 0
      src/utils/md5.js
  27. 42 0
      src/utils/tool.js
  28. 232 0
      src/utils/utils.js

+ 145 - 0
src/components/zj-container/zj-fiex-column.vue

@@ -0,0 +1,145 @@
+<template>
+  <view
+    :class="{
+      'zj-page-container': true,
+      'zj-page-container-column': direction === 'column'
+    }"
+    :style="{
+      width,
+      height,
+      background
+    }"
+  >
+    <slot name="before"></slot>
+    <view :class="['zj-page-fill', zjPageFillClass]">
+      <view class="zj-page-fill-absolute">
+        <template v-if="scroll">
+          <scroll-view
+            class="zj-page-fill-scroll"
+            scroll-y
+            enable-flex
+            @scrolltoupper="
+              (...p) => {
+                $emit('scrolltoupper', p)
+              }
+            "
+            @scrolltolower="
+              (...p) => {
+                $emit('scrolltolower', p)
+              }
+            "
+            @scroll="
+              (...p) => {
+                $emit('scroll', p)
+              }
+            "
+            @refresherpulling="
+              (...p) => {
+                $emit('refresherpulling', p)
+              }
+            "
+            @refresherrefresh="
+              (...p) => {
+                $emit('refresherrefresh', p)
+              }
+            "
+            @refresherrestore="
+              (...p) => {
+                $emit('refresherrestore', p)
+              }
+            "
+            @refresherabort="
+              (...p) => {
+                $emit('refresherabort', p)
+              }
+            "
+            :refresher-enabled="refresherEnabled"
+            :refresher-triggered="refresherTriggered"
+          >
+            <slot></slot>
+          </scroll-view>
+        </template>
+        <template v-else>
+          <slot></slot>
+        </template>
+      </view>
+    </view>
+    <slot name="after"></slot>
+  </view>
+</template>
+
+<script>
+export default {
+  props: {
+    background: {
+      type: String,
+      default: ''
+    },
+    width: {
+      type: String,
+      default: '100%'
+    },
+    height: {
+      type: String,
+      default: '100%'
+    },
+    direction: {
+      type: String,
+      default: 'column'
+    },
+    scroll: {
+      type: Boolean,
+      default: true
+    },
+    zjPageFillClass: {
+      type: String,
+      default: ''
+    },
+    refresherEnabled: {
+      type: Boolean,
+      default: false
+    },
+    refresherTriggered: {
+      type: Boolean,
+      default: false
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.zj-page-container {
+  display: flex;
+  display: -webkit-flex;
+  box-sizing: border-box;
+}
+
+.zj-page-container-row {
+  flex-direction: row;
+}
+
+.zj-page-container-column {
+  flex-direction: column;
+}
+
+.zj-page-fill {
+  box-sizing: border-box;
+  flex: 1;
+  overflow: hidden;
+  position: relative;
+
+  .zj-page-fill-absolute {
+    position: absolute;
+    top: 0;
+    right: 0;
+    bottom: 0;
+    left: 0;
+  }
+
+  .zj-page-fill-scroll {
+    width: 100%;
+    height: 100%;
+    box-sizing: border-box;
+  }
+}
+</style>

+ 144 - 0
src/components/zj-container/zj-fiex-row.vue

@@ -0,0 +1,144 @@
+<template>
+  <view
+    :class="{
+      'zj-page-container': true,
+      'zj-page-container-row': direction === 'row'
+    }"
+    :style="{
+      width,
+      height,
+      background
+    }"
+  >
+    <slot name="before"></slot>
+    <view :class="['zj-page-fill', zjPageFillClass]">
+      <view class="zj-page-fill-absolute">
+        <template v-if="scroll">
+          <scroll-view
+            class="zj-page-fill-scroll"
+            scroll-y
+            scroll-x
+            enable-flex
+            @scrolltoupper="
+              (...p) => {
+                $emit('scrolltoupper', p)
+              }
+            "
+            @scrolltolower="
+              (...p) => {
+                $emit('scrolltolower', p)
+              }
+            "
+            @scroll="
+              (...p) => {
+                $emit('scroll', p)
+              }
+            "
+            @refresherpulling="
+              (...p) => {
+                $emit('refresherpulling', p)
+              }
+            "
+            @refresherrefresh="
+              (...p) => {
+                $emit('refresherrefresh', p)
+              }
+            "
+            @refresherrestore="
+              (...p) => {
+                $emit('refresherrestore', p)
+              }
+            "
+            @refresherabort="
+              (...p) => {
+                $emit('refresherabort', p)
+              }
+            "
+          >
+            <slot></slot>
+          </scroll-view>
+        </template>
+        <template v-else>
+          <slot></slot>
+        </template>
+      </view>
+    </view>
+    <slot name="after"></slot>
+  </view>
+</template>
+
+<script>
+export default {
+  props: {
+    background: {
+      type: String,
+      default: ''
+    },
+    width: {
+      type: String,
+      default: '100%'
+    },
+    height: {
+      type: String,
+      default: '100%'
+    },
+    direction: {
+      type: String,
+      default: 'column'
+    },
+    scroll: {
+      type: Boolean,
+      default: true
+    },
+    zjPageFillClass: {
+      type: String,
+      default: ''
+    },
+    refresherEnabled: {
+      type: Boolean,
+      default: false
+    },
+    refresherTriggered: {
+      type: Boolean,
+      default: false
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.zj-page-container {
+  display: flex;
+  display: -webkit-flex;
+  box-sizing: border-box;
+}
+
+.zj-page-container-row {
+  flex-direction: row;
+}
+
+.zj-page-container-column {
+  flex-direction: column;
+}
+
+.zj-page-fill {
+  box-sizing: border-box;
+  flex: 1;
+  overflow: hidden;
+  position: relative;
+
+  .zj-page-fill-absolute {
+    position: absolute;
+    top: 0;
+    right: 0;
+    bottom: 0;
+    left: 0;
+  }
+
+  .zj-page-fill-scroll {
+    width: 100%;
+    height: 100%;
+    box-sizing: border-box;
+  }
+}
+</style>

+ 25 - 0
src/components/zj-container/zj-page-container.vue

@@ -0,0 +1,25 @@
+<template>
+  <view class="page-bottom" :style="{ background }">
+    <slot></slot>
+  </view>
+</template>
+
+<script>
+export default {
+  props: {
+    background: {
+      type: String,
+      default: ''
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.page-bottom {
+  width: 100%;
+  height: 100vh;
+  box-sizing: border-box;
+  padding-bottom: env(safe-area-inset-bottom);
+}
+</style>

+ 206 - 0
src/components/zj-upload/index.vue

@@ -0,0 +1,206 @@
+<template>
+  <view class="file-upload-container">
+    <view class="file-upload-view" v-for="(item, index) in files" :key="index">
+      <view class="file-upload-ckick" @click="imgView(index)">
+        <image v-if="item.url" mode="aspectFit" :src="imageUrl + item.url" style="width: 100%; height: 100%"> </image>
+        <template v-else>
+          <image mode="aspectFit" :src="item.loUrl" style="width: 100%; height: 100%"> </image>
+          <view class="mack" @tap.stop="() => {}"></view>
+          <image @tap.stop="() => {}" class="uploadImg" mode="aspectFit" src="/static/images/upload/loading.png">
+          </image>
+        </template>
+        <template v-if="!disabled">
+          <text class="iconfont icon-guanbi1 delImg" @tap.stop="del(index)"></text>
+        </template>
+      </view>
+    </view>
+    <template v-if="!disabled">
+      <view v-if="count === 0 ? true : count - files.length" class="file-upload-view" @click="upload">
+        <view class="file-upload-ckick">
+          <text class="iconfont icon-paizhao uploadImg"></text>
+        </view>
+      </view>
+    </template>
+  </view>
+</template>
+
+<script>
+import { uploadImgFull } from '@/common/utils/util.js'
+import { b64_md5 } from '@/utils/md5.js'
+import loadingImg from './loading.png'
+export default {
+  props: {
+    disabled: {
+      type: Boolean,
+      default: false
+    },
+    count: {
+      type: Number,
+      default: 0
+    },
+    fileList: {
+      type: Array,
+      default: () => []
+    }
+  },
+  data() {
+    return {
+      imageUrl: this.$imageUrl,
+      files: this.setFileVal(this.fileList)
+    }
+  },
+  watch: {
+    fileList() {
+      this.files = this.setFileVal(this.fileList)
+    },
+    files: {
+      handler(newName, oldName) {
+        if (newName.every(item => (item.url ? true : false))) {
+          this.$emit(
+            'getFiles',
+            newName.map(item => item.url)
+          )
+        }
+      },
+      deep: true
+    }
+  },
+  methods: {
+    setFileVal(arr) {
+      return arr.map(item => {
+        if (typeof item == 'string') {
+          return {
+            url: item,
+            key: b64_md5(item)
+          }
+        } else {
+          return item
+        }
+      })
+    },
+    upload() {
+      uni.chooseImage({
+        count: this.count === 0 ? 0 : this.count - this.files.length,
+        sizeType: ['original'],
+        success: async res => {
+          const leng = res.tempFiles.length
+          for (var file of res.tempFiles) {
+            this.files.push({
+              url: false,
+              key: b64_md5(file.path),
+              loUrl: file.path
+            })
+          }
+          for (var i = 0; i < leng; i++) {
+            var data = await uploadImgFull(res.tempFiles[i])
+            var obj = this.files.find(item => item.key === b64_md5(res.tempFiles[i].path))
+            if (obj) {
+              obj.url = data.url
+              obj.key = b64_md5(data.url)
+              delete obj.loUrl
+            }
+          }
+        },
+        fail: err => {
+          console.log(err)
+        }
+      })
+    },
+    del(index) {
+      this.files.splice(index, 1)
+    },
+    imgView(index) {
+      var list = this.files.map(item => {
+        if (item.url) {
+          return this.imageUrl + item.url
+        } else {
+          return loadingImg
+        }
+      })
+      uni.previewImage({
+        current: index,
+        urls: list
+      })
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.file-upload-container {
+  width: 100%;
+  height: 100%;
+  display: flex;
+  flex-wrap: wrap;
+  justify-content: space-between;
+
+  .file-upload-view {
+    display: inline-block;
+    margin-bottom: 20rpx;
+
+    &:nth-last-of-type(-n + 2) {
+      margin-bottom: 0;
+    }
+
+    .file-upload-ckick {
+      width: 300rpx;
+      height: 190rpx;
+      background: #ffffff;
+      border-radius: 20rpx;
+      opacity: 1;
+      border: 1rpx solid #e4e4e4;
+      box-sizing: border-box;
+      padding: 10rpx;
+      position: relative;
+      display: flex;
+      justify-content: center;
+      align-items: center;
+
+      .mack {
+        width: 100%;
+        height: 100%;
+        position: absolute;
+        top: 50%;
+        left: 50%;
+        transform: translate(-50%, -50%);
+        z-index: 2;
+        background: rgba(0, 0, 0, 0.2);
+      }
+
+      .icon-paizhao {
+        background: $theme-color;
+        color: #ffffff;
+        font-size: 40rpx;
+        border-radius: 50%;
+        text-align: center;
+        line-height: 80rpx;
+      }
+
+      .uploadImg {
+        width: 80rpx;
+        height: 80rpx;
+        position: absolute;
+        top: 50%;
+        left: 50%;
+        transform: translate(-50%, -50%);
+        z-index: 3;
+      }
+
+      .delImg {
+        position: absolute;
+        top: -16rpx;
+        right: -16rpx;
+        z-index: 2;
+        width: 40rpx;
+        height: 40rpx;
+        background: $minor-color;
+        color: #ffffff;
+        border-radius: 50%;
+        text-align: center;
+        line-height: 40rpx;
+        font-size: 28rpx;
+      }
+    }
+  }
+}
+</style>

BIN
src/components/zj-upload/loading.png


+ 66 - 0
src/packageEnter/components/zj-date.vue

@@ -0,0 +1,66 @@
+<template>
+  <picker mode="date" :value="date" @change="bindDateChange">
+    <text>{{ date }}</text>
+  </picker>
+</template>
+<script>
+export default {
+  props: {
+    value: {
+      type: String,
+      default: '',
+    },
+  },
+  data() {
+    return {
+      date: this.value ? this.getTime(this.value) : this.getDate(),
+    };
+  },
+  watch: {
+    value() {
+      this.date = this.getTime(this.value);
+    },
+  },
+  mounted() {
+    this.$emit('input', this.date);
+  },
+  methods: {
+    getDate(type) {
+      const date = new Date();
+      let year = date.getFullYear();
+      let month = date.getMonth() + 1;
+      let day = date.getDate();
+      if (type === 'start') {
+        year = year - 60;
+      } else if (type === 'end') {
+        year = year + 2;
+      }
+      month = month > 9 ? month : '0' + month;
+      day = day > 9 ? day : '0' + day;
+      return `${year}-${month}-${day}`;
+    },
+    getTime(val) {
+      const date = new Date(val);
+      let year = date.getFullYear();
+      let month = date.getMonth() + 1;
+      let day = date.getDate();
+      month = month > 9 ? month : '0' + month;
+      day = day > 9 ? day : '0' + day;
+      return `${year}-${month}-${day}`;
+    },
+    bindDateChange: function (e) {
+      this.date = e.detail.value;
+      this.$emit('input', this.date);
+    },
+  },
+};
+</script>
+<style lang="scss" scoped>
+picker {
+  width: 100%;
+  height: 100%;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+}
+</style>

+ 48 - 0
src/packageEnter/pages/insurance/detailsAgreement/index.vue

@@ -0,0 +1,48 @@
+<template>
+  <zj-page-container>
+    <zj-fiex-column>
+      <view class="page-content" v-if="!loading">
+        <view class="rich-text-content" v-show="content">
+          <rich-text :nodes="content"></rich-text>
+        </view>
+      </view>
+    </zj-fiex-column>
+  </zj-page-container>
+</template>
+<script>
+import ZjFiexColumn from '@/components/zj-container/zj-fiex-column.vue'
+import ZjPageContainer from '@/components/zj-container/zj-page-container.vue'
+export default {
+  components: {
+    ZjFiexColumn,
+    ZjPageContainer
+  },
+  data() {
+    return {
+      loading: true,
+      content: ''
+    }
+  },
+  onLoad(options) {
+    if (options.id) {
+      uni.showLoading({
+        title: '加载中'
+      })
+      this.$api.post('/worker/agreement', options).then(res => {
+        var { context, agreementName } = res.data
+        uni.setNavigationBarTitle({
+          title: agreementName
+        })
+        this.content = context
+        this.$nextTick(() => {
+          this.loading = false
+          uni.hideLoading()
+        })
+      })
+    }
+  }
+}
+</script>
+<style lang="scss" scoped>
+@import './style.scss';
+</style>

+ 8 - 0
src/packageEnter/pages/insurance/detailsAgreement/style.scss

@@ -0,0 +1,8 @@
+.page-content {
+	box-sizing: border-box;
+	padding: 30rpx;
+
+	.rich-text-content {
+		margin-bottom: 26rpx;
+	}		
+}

+ 142 - 0
src/packageEnter/pages/insurance/determineInfo/index.vue

@@ -0,0 +1,142 @@
+<template>
+  <zj-page-container>
+    <zj-fiex-column>
+      <view class="page-content" v-if="!loading">
+        <view class="module-view">
+          <view class="module-view-single">
+            <text>被保险人</text>
+            <text>{{ info.workerName }}</text>
+          </view>
+          <view class="module-view-single">
+            <text>被保险人身份证号</text>
+            <text>{{ info.workerIdcard }}</text>
+          </view>
+          <view class="module-view-single">
+            <text>保单名称</text>
+            <text>{{ info.policyName }}</text>
+          </view>
+          <view class="module-view-single">
+            <text>生效日期</text>
+            <text>{{ info.startTime }}</text>
+          </view>
+          <view class="module-view-single">
+            <text>保障截止时间</text>
+            <text>{{ info.endTime }}</text>
+          </view>
+        </view>
+        <view class="module-view">
+          <view class="module-view-single">
+            <text>付款方式</text>
+            <text>全额支付</text>
+          </view>
+          <view class="module-view-single">
+            <text>保费</text>
+            <text style="color: #e95505">{{ info.payAmount }}</text>
+          </view>
+        </view>
+      </view>
+      <view slot="after" class="bottom-reservation">
+        <view class="gouxuan">
+          <label :disabled="loading" class="radio" @click="checked = !checked">
+            <radio :checked="checked" />
+            <text>请阅读</text>
+          </label>
+          <text v-for="(item, index) in insureAgreeList" :key="index" @click="goDetailsAgreement(item)">{{
+            item.agreementName
+          }}</text>
+          <text v-if="index < insureAgreeList.length - 1">/</text>
+        </view>
+        <view class="btns">
+          <u-button :disabled="loading" type="primary" @click="goback">暂不同意</u-button>
+          <u-button :disabled="loading || !checked" type="primary" @click="pay">同意并继续</u-button>
+        </view>
+      </view>
+    </zj-fiex-column>
+  </zj-page-container>
+</template>
+<script>
+import ZjFiexColumn from '@/components/zj-container/zj-fiex-column.vue'
+import ZjPageContainer from '@/components/zj-container/zj-page-container.vue'
+import { payMoney } from '@/utils/utils.js'
+import { countdown } from '@/utils/tool.js'
+import { weixinPay, mini_env } from '@/common/utils/util.js'
+export default {
+  components: {
+    ZjFiexColumn,
+    ZjPageContainer
+  },
+  data() {
+    return {
+      loading: true,
+      checked: false,
+      info: {},
+      insureAgreeList: [],
+      websitId: '',
+      id: ''
+    }
+  },
+  onLoad({ websitId, id }) {
+    this.id = id
+    this.websitId = websitId
+    this.$api.post('/worker/buy', { policyId: this.id, websitId }).then(res => {
+      this.info = res.data
+      this.$nextTick(() => {
+        this.loading = false
+        uni.hideLoading()
+      })
+    })
+    this.$api.post('/worker/detail', { id }).then(res => {
+      var { agreements, policyName, text } = res.data
+      this.insureAgreeList = agreements
+    })
+  },
+  methods: {
+    async pay() {
+      mini_env(bool => {
+        this.$api.post('/worker/pay', { policyOrderId: this.info.id }).then(res => {
+          // 小程序环境
+          if (bool) {
+            uniWebview.navigateTo({
+              url: `/pages/pay/pay?${Object.entries({
+                ...res.data,
+                payPackage: res.data.payPackage.split('=')[0] || '',
+                payPackageVal: res.data.payPackage.split('=')[1] || ''
+              })
+                .map(item => item.join('='))
+                .join('&')}`
+            })
+          }
+          // h5环境
+          else {
+            weixinPay(res.data, function (res) {
+              setTimeout(() => {
+                that.$navToPage(
+                  {
+                    url: '/packageEnter/pages/insurance/myInsurance/index'
+                  },
+                  'reLaunch'
+                )
+              }, 1000)
+            })
+          }
+        })
+      })
+    },
+    goback() {
+      uni.navigateBack({
+        delta: 1
+      })
+    },
+    goDetailsAgreement(item) {
+      if (item.id) {
+        uni.navigateTo({
+          url: `/packageEnter/pages/insurance/detailsAgreement/index?id=${item.id}`
+        })
+      }
+    }
+  }
+}
+</script>
+<style lang="scss" scoped>
+@import './style.scss';
+</style>

+ 98 - 0
src/packageEnter/pages/insurance/determineInfo/style.scss

@@ -0,0 +1,98 @@
+.page-content {
+		min-height: 100%;
+		box-sizing: border-box;
+		padding: 30rpx;
+		background: #F7F7F7;
+
+		.module-view {
+			width: 100%;
+			background: #FFFFFF;
+			border-radius: 20rpx;
+
+			&:not(:last-child) {
+				margin-bottom: 20rpx;
+			}
+
+			.module-view-single {
+				width: 100%;
+				height: 112rpx;
+				display: flex;
+				justify-content: space-between;
+				align-items: center;
+				box-sizing: border-box;
+				padding: 0 30rpx;
+
+				text:nth-child(1) {
+					font-size: 32rpx;
+					font-family: Source Han Sans CN-Regular, Source Han Sans CN;
+					font-weight: 400;
+					color: #0B2853;
+				}
+
+				text:nth-child(2) {
+					font-size: 32rpx;
+					font-family: Source Han Sans CN-Regular, Source Han Sans CN;
+					font-weight: 400;
+					color: #B5BECB;
+				}
+
+				&:not(:last-child) {
+					border-bottom: 2rpx solid rgba(229, 229, 229, 1);
+				}
+			}
+		}
+	}
+
+	.bottom-reservation {
+		box-sizing: border-box;
+		padding: 20rpx 30rpx ;
+
+		.gouxuan {
+			margin-bottom: 26rpx;
+			display: flex;
+			align-items: center;
+			color: #3887FF;
+
+			.radio {
+				display: flex;
+				align-items: center;
+
+				text {
+					font-size: 28rpx;
+					font-family: Source Han Sans CN-Regular, Source Han Sans CN;
+					font-weight: 400;
+					margin-right: 16rpx;
+					color: #333333;
+				}
+			}
+		}
+
+		.btns {
+			width: 100%;
+			display: flex;
+			flex-direction: row;
+			justify-content: space-between;
+
+			::v-deep button {
+
+				height: 80rpx;
+				margin: 0;
+				font-size: 32rpx;
+				font-family: Source Han Sans CN-Regular, Source Han Sans CN;
+				font-weight: 400;
+
+				&:nth-child(1) {
+					width: 36%;
+					background: #fff;
+					border: 2rpx solid #B5BECB;
+					color: #333333;
+				}
+
+				&:nth-child(2) {
+					width: 60%;
+					background: #3D8FFD;
+					color: #FFFFFF;
+				}
+			}
+		}
+	}

+ 95 - 0
src/packageEnter/pages/insurance/insuranceContract/index.vue

@@ -0,0 +1,95 @@
+<template>
+  <zj-page-container>
+    <zj-fiex-column>
+      <view class="page-content" v-if="!loading">
+        <view class="rich-text-content" v-show="content">
+          <rich-text :nodes="content"></rich-text>
+        </view>
+        <view class="please-read">
+          <view class="please-read-title"> 请阅读: </view>
+          <view
+            class="please-read-contract"
+            v-for="(item, index) in insureAgreeList"
+            :key="index"
+            @click="goDetailsAgreement(item)"
+          >
+            《{{ item.agreementName }}》
+          </view>
+        </view>
+      </view>
+      <view slot="after" class="bottom-reservation">
+        <u-button :disabled="ins > 0 ? true : false" type="primary" @click="gopay"
+          >了解并继续{{ ins > 0 ? `(${ins}s)` : '' }}
+        </u-button>
+      </view>
+    </zj-fiex-column>
+  </zj-page-container>
+</template>
+<script>
+import ZjFiexColumn from '@/components/zj-container/zj-fiex-column.vue'
+import ZjPageContainer from '@/components/zj-container/zj-page-container.vue'
+import { countdown } from '@/utils/tool.js'
+export default {
+  components: {
+    ZjFiexColumn,
+    ZjPageContainer
+  },
+  data() {
+    return {
+      loading: true,
+      content: '',
+      insureAgreeList: [],
+      ins: 0,
+      djs: countdown(
+        s => {
+          this.ins = s
+        },
+        () => {
+          this.ins = 0
+        },
+        5
+      ),
+      websitId: '',
+      id: ''
+    }
+  },
+  onLoad({ websitId, id }) {
+    this.id = id
+    this.websitId = websitId
+    uni.showLoading({
+      title: '加载中'
+    })
+
+    this.$api.post('/worker/detail', { id }).then(res => {
+      var { agreements, policyName, text } = res.data
+      uni.setNavigationBarTitle({
+        title: policyName
+      })
+      this.content = text
+      this.insureAgreeList = agreements
+      this.$nextTick(() => {
+        this.loading = false
+        this.djs.start()
+        uni.hideLoading()
+      })
+    })
+  },
+  methods: {
+    goDetailsAgreement(item) {
+      if (item.id) {
+        uni.navigateTo({
+          url: `/packageEnter/pages/insurance/detailsAgreement/index?id=${item.id}`
+        })
+      }
+    },
+    gopay() {
+      uni.navigateTo({
+        url: `/packageEnter/pages/insurance/determineInfo/index?websitId=${this.websitId}&id=${this.id}`
+      })
+    }
+  }
+}
+</script>
+<style lang="scss" scoped>
+@import './style.scss';
+</style>

+ 39 - 0
src/packageEnter/pages/insurance/insuranceContract/style.scss

@@ -0,0 +1,39 @@
+.page-content {
+		box-sizing: border-box;
+		padding: 30rpx;
+
+		.rich-text-content {
+			margin-bottom: 26rpx;
+		}
+
+		.please-read {
+			.please-read-title {
+				font-size: 28rpx;
+				font-family: Source Han Sans CN-Regular, Source Han Sans CN;
+				font-weight: 400;
+				color: #0B2853;
+				line-height: 52rpx;
+			}
+
+			.please-read-contract {
+				font-size: 28rpx;
+				font-family: Source Han Sans CN-Regular, Source Han Sans CN;
+				font-weight: 400;
+				color: #3D8FFD;
+				line-height: 52rpx;
+			}
+		}
+	}
+
+	.bottom-reservation {
+		height: 120rpx;
+		box-sizing: border-box;
+		padding: 20rpx 30rpx;
+
+		::v-deep button {
+			font-size: 32rpx;
+			font-family: Source Han Sans CN-Regular, Source Han Sans CN;
+			font-weight: 400;
+			color: #FFFFFF;
+		}
+	}

+ 219 - 0
src/packageEnter/pages/insurance/insurancePolicy/index.vue

@@ -0,0 +1,219 @@
+<template>
+  <!-- 线下购买上传保单信息 -->
+  <zj-page-container>
+    <zj-fiex-column>
+      <view class="page-content">
+        <view class="page-content-view">
+          <view class="" style="position: relative">
+            <view class="dl-title">
+              <text class="dl-label">保单生效日期</text>
+            </view>
+            <view class="dl-md">
+              <zj-fiex-row>
+                <view slot="before" style="width: 45%; height: 100%">
+                  <zj-date v-model="fromData.startTime" />
+                </view>
+                <view class="shijianzhi"> 至 </view>
+                <view slot="after" style="width: 45%; height: 100%">
+                  <zj-date v-model="fromData.endTime" />
+                </view>
+              </zj-fiex-row>
+            </view>
+            <view class="dl-md">
+              <zj-fiex-row>
+                <view slot="before" class="dl-label">保单号</view>
+                <input class="dl-input" placeholder="请输入" v-model="fromData.insureBill" />
+              </zj-fiex-row>
+            </view>
+            <view class="dl-md" v-if="disabled">
+              <zj-fiex-row>
+                <view slot="before" class="dl-label">保险公司</view>
+                <input class="dl-input" placeholder="请输入" v-model="fromData.insureCompany" />
+              </zj-fiex-row>
+            </view>
+            <view class="dl-md" v-else>
+              <zj-fiex-row>
+                <view slot="before" class="dl-label">保险公司</view>
+                <picker @change="bindPickerChange" :value="index" :range="INSURE_COMPANY" range-key="dictValue">
+                  <view class="dl-input" style="height: 110rpx; line-height: 110rpx">
+                    {{ fromData.insureCompany || '请选择' }}</view
+                  >
+                </picker>
+              </zj-fiex-row>
+            </view>
+            <view v-if="disabled" class="page-content-view-zz" @tap.stop="() => {}"> </view>
+          </view>
+          <view class="dl-title" style="margin-bottom: 20rpx">
+            <text class="dl-label">保单图片</text>
+          </view>
+          <view class="">
+            <zj-upload
+              :disabled="disabled"
+              :fileList="fileList"
+              @getFiles="
+                list => {
+                  fileList = list
+                }
+              "
+            />
+          </view>
+        </view>
+        <template v-if="!disabled">
+          <view class="prompt" v-if="fromData.examineStatus"> 失败原因:{{ fromData.examineRemark }} </view>
+          <u-button type="primary" @click="submit">提交审核</u-button>
+        </template>
+      </view>
+    </zj-fiex-column>
+  </zj-page-container>
+</template>
+<script>
+import ZjFiexColumn from '@/components/zj-container/zj-fiex-column.vue'
+import ZjFiexRow from '@/components/zj-container/zj-fiex-row.vue'
+import ZjPageContainer from '@/components/zj-container/zj-page-container.vue'
+import ZjDate from '@/packageEnter/components/zj-date.vue'
+import ZjUpload from '@/components/zj-upload/index.vue'
+export default {
+  components: {
+    ZjFiexRow,
+    ZjFiexColumn,
+    ZjPageContainer,
+    ZjDate,
+    ZjUpload
+  },
+  data() {
+    return {
+      disabled: true,
+      fromData: {
+        startTime: '',
+        endTime: '',
+        insureBill: '',
+        insureCompany: '',
+        insureWorkerCommercialFileList: [],
+        examineStatus: ''
+      },
+      fileList: [],
+      websitId: '',
+      INSURE_COMPANY: [],
+      index: 0
+    }
+  },
+  async onLoad({ websitId }) {
+    this.websitId = websitId
+    this.$axios({
+      url: insurance.insureCommercialDetail,
+      params: {
+        websitId: this.websitId
+      }
+    }).then(res => {
+      console.log(res.data)
+      if (res.data.endTime) {
+        //当前时间
+        let d1 = new Date()
+        //到期时间
+        let d2 = res.data.endTime
+        //转换为标准时间"2019/12/29 23:59:59"
+        d2 = d2.replace(/-/g, '/')
+        d2 = new Date(d2)
+        //如果当前时间大于到期时间
+        if (d1.valueOf() > d2.valueOf()) {
+          this.disabled = false
+        } else {
+          this.disabled = true
+        }
+      } else {
+        this.disabled = false
+      }
+      for (var key in res.data) {
+        if (~['startTime', 'endTime'].indexOf(key)) {
+          if (res.data[key]) {
+            this.fromData[key] = res.data[key]
+          }
+        } else {
+          this.fromData[key] = res.data[key]
+        }
+      }
+    })
+
+    this.INSURE_COMPANY = await this.$getDictList({
+      dictType: 'INSURE_COMPANY'
+    })
+    console.log(this.INSURE_COMPANY, '---------')
+  },
+  watch: {
+    'fromData.insureWorkerCommercialFileList'() {
+      this.fileList = (this.fromData.insureWorkerCommercialFileList || []).map(item => item.fileUrl)
+    }
+  },
+  methods: {
+    bindPickerChange(e) {
+      this.fromData.insureCompany = this.INSURE_COMPANY[e.detail.value]
+        ? this.INSURE_COMPANY[e.detail.value].dictValue
+        : ''
+      console.log(this.fromData.insureCompany)
+    },
+    submit() {
+      console.log(this.fromData, this.fileList)
+      // 校验
+      for (var key of ['startTime', 'endTime', 'insureBill', 'insureCompany', 'insureWorkerCommercialFileList']) {
+        if (!this.fromData[key]) {
+          if (key === 'insureWorkerCommercialFileList') {
+            if (!this.fileList.length) {
+              this.$toast(
+                `${
+                  {
+                    startTime: '证书有效开始时间',
+                    endTime: '证书有效结束时间',
+                    insureBill: '保险单',
+                    insureCompany: '保险公司',
+                    insureWorkerCommercialFileList: '保单图片'
+                  }[key]
+                }不能为空`
+              )
+              return
+            }
+          } else {
+            this.$toast(
+              `${
+                {
+                  startTime: '证书有效开始时间',
+                  endTime: '证书有效结束时间',
+                  insureBill: '保险单',
+                  insureCompany: '保险公司',
+                  insureWorkerCommercialFileList: '保单图片'
+                }[key]
+              }不能为空`
+            )
+            return
+          }
+        }
+      }
+      // 提交
+      this.$axios({
+        url: insurance.insureCommercialSubmit,
+        type: 'json',
+        params: {
+          ...this.fromData,
+          startTime: `${this.fromData.startTime} 00:00:00`,
+          endTime: `${this.fromData.endTime} 23:59:59`,
+          insureWorkerCommercialFileList: this.fileList.map(url => ({
+            fileUrl: url
+          })),
+          websitId: this.websitId
+        }
+      }).then(res => {
+        uni.$emit('updateUserInfo')
+        uni.showToast({
+          title: `提交成功`,
+          duration: 2000
+        })
+        uni.switchTab({
+          url: `/pages/task/index`
+        })
+      })
+    }
+  }
+}
+</script>
+<style lang="scss" scoped>
+@import './style.scss';
+</style>

+ 68 - 0
src/packageEnter/pages/insurance/insurancePolicy/style.scss

@@ -0,0 +1,68 @@
+.page-content {
+	min-height: 100%;
+	box-sizing: border-box;
+	padding: 30rpx;
+	background: #f7f7f7;
+	.page-content-view{
+		width: 100%;
+		box-sizing: border-box;
+		padding: 30rpx;
+		background: #FFFFFF;
+		border-radius: 20rpx;
+		margin-bottom: 56rpx;
+		position: relative;
+		.page-content-view-zz{
+			top: 0;
+			left: 0;
+			right: 0;
+			bottom: 0;
+			position: absolute;
+			width: 100%;
+			height: 100%;
+			z-index: 999999;
+		}
+	}
+	.dl-label{
+		width: 165rpx;
+		font-size: 32rpx;
+		font-family: Source Han Sans CN-Regular, Source Han Sans CN;
+		font-weight: 400;
+		color: #87919F;
+		line-height: 32rpx;
+		display: inline-block;
+	}
+	.dl-input{
+		width: 100%;
+		height: 100%;
+	}
+	.dl-md{
+		width: 100%;
+		height: 112rpx;
+		border-bottom: 2rpx solid  rgba(229,229,229,1);
+		.dl-label{
+			line-height: 112rpx;
+		}
+		&:nth-child(4){
+			margin-bottom: 20rpx;
+		}
+	}
+	.shijianzhi{
+		width: 100%;
+		height: 100%;
+		line-height: 112rpx;
+		text-align: center;
+	}
+	::v-deep button {
+		font-size: 32rpx;
+		font-family: Source Han Sans CN-Regular, Source Han Sans CN;
+		font-weight: 400;
+		color: #FFFFFF;
+	}
+	.prompt{
+		font-size: 28rpx;
+		font-family: Source Han Sans CN-Regular, Source Han Sans CN;
+		font-weight: 400;
+		color: #FE894A;
+		margin-bottom: 20rpx;
+	}
+}

+ 84 - 0
src/packageEnter/pages/insurance/myInsurance/index.vue

@@ -0,0 +1,84 @@
+<template>
+  <view class="myInsurance">
+    <view class="myInsuranceCart" v-for="(item, index) in list" :key="index" @click="gopage(item)">
+      <view class="myInsuranceCartbuju xiangxia">
+        <view class="">
+          {{ item.policyName }}
+        </view>
+        <view class="" style="color: red">
+          {{ { BZZ: '保障中', YSX: '失效', DSX: '待生效' }[item.status] }}
+        </view>
+      </view>
+      <view class="">
+        <view class="xiangxia"> 所属网点:{{ item.websitName }} </view>
+        <view class="xiangxia"> 保单类型:{{ { AC: '意外险', EM: '雇主险', IN: '工伤险' }[item.policyType] }} </view>
+        <view class="xiangxia"> 保单编号:{{ item.policyOrder }} </view>
+        <view class="xiangxia"> 保单金额:{{ item.policyPrice }} </view>
+        <view class="xiangxia"> 有效时间:{{ item.startTime }}~{{ item.endTime }} </view>
+      </view>
+    </view>
+  </view>
+</template>
+<script>
+export default {
+  data() {
+    return {
+      list: [],
+      websitId: ''
+    }
+  },
+  onShow() {
+    uni.showLoading({
+      title: '加载中'
+    })
+    this.$api.post('/worker/myPolicy', { pageNum: 1, pageSize: -1 }).then(res => {
+      this.list = res.data
+      this.$nextTick(() => {
+        uni.hideLoading()
+      })
+    })
+  },
+  onPullDownRefresh() {
+    this.$api.post('/worker/myPolicy', { pageNum: 1, pageSize: -1 }).then(res => {
+      this.list = res.data
+      this.$nextTick(() => {
+        uni.stopPullDownRefresh()
+      })
+    })
+  },
+  methods: {
+    gopage(item) {
+      this.$navPage(`/packageEnter/pages/insurance/policyParticulars/index?id=${item.id}`)
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.myInsurance {
+  box-sizing: border-box;
+  padding: 20rpx;
+  padding-top: 40rpx;
+
+  .myInsuranceCart {
+    width: 100%;
+    height: auto;
+    box-sizing: border-box;
+    padding: 20rpx;
+    margin-bottom: 20rpx;
+    box-shadow: 2.8px 2.8px 2.2px rgba(0, 0, 0, 0.02), 6.7px 6.7px 5.3px rgba(0, 0, 0, 0.028),
+      12.5px 12.5px 10px rgba(0, 0, 0, 0.035), 22.3px 22.3px 17.9px rgba(0, 0, 0, 0.042),
+      41.8px 41.8px 33.4px rgba(0, 0, 0, 0.05), 100px 100px 80px rgba(0, 0, 0, 0.07);
+    border-radius: 10rpx;
+
+    .myInsuranceCartbuju {
+      display: flex;
+      justify-content: space-between;
+    }
+
+    .xiangxia {
+      margin-bottom: 10rpx;
+    }
+  }
+}
+</style>

+ 68 - 0
src/packageEnter/pages/insurance/myInsuranceBuy/index.vue

@@ -0,0 +1,68 @@
+<template>
+  <view class="myInsurance">
+    <view class="myInsuranceCart" v-for="(item, index) in list" :key="index" @click="gopage(item)">
+      <view class="">
+        <view class="xiangxia"> 承保公司:{{ item.company }} </view>
+        <view class="xiangxia"> 保单名称:{{ item.policyName }} </view>
+        <view class="xiangxia"> 保单编号:{{ item.policyNumber }} </view>
+        <view class="xiangxia"> 保单金额:{{ item.policyPrice }} </view>
+        <view class="xiangxia"> 有效时间:{{ item.startTime }}~{{ item.endTime }} </view>
+      </view>
+    </view>
+  </view>
+</template>
+<script>
+export default {
+  data() {
+    return {
+      list: [],
+      websitId: ''
+    }
+  },
+  onLoad({ websitId }) {
+    uni.showLoading({
+      title: '加载中'
+    })
+    this.$api.post('/worker/policy', { pageNum: 1, pageSize: -1, websitId }).then(res => {
+      this.list = res?.data?.records
+      this.$nextTick(() => {
+        uni.hideLoading()
+      })
+    })
+  },
+  methods: {
+    gopage(item) {
+      this.$navPage(`/packageEnter/pages/insurance/policyParticulars/index?id=${item.id}&websitId=${this.websitId}`)
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.myInsurance {
+  box-sizing: border-box;
+  padding: 20rpx;
+  padding-top: 40rpx;
+
+  .myInsuranceCart {
+    width: 100%;
+    height: auto;
+    box-sizing: border-box;
+    padding: 20rpx;
+    margin-bottom: 20rpx;
+    box-shadow: 2.8px 2.8px 2.2px rgba(0, 0, 0, 0.02), 6.7px 6.7px 5.3px rgba(0, 0, 0, 0.028),
+      12.5px 12.5px 10px rgba(0, 0, 0, 0.035), 22.3px 22.3px 17.9px rgba(0, 0, 0, 0.042),
+      41.8px 41.8px 33.4px rgba(0, 0, 0, 0.05), 100px 100px 80px rgba(0, 0, 0, 0.07);
+    border-radius: 10rpx;
+
+    .myInsuranceCartbuju {
+      display: flex;
+      justify-content: space-between;
+    }
+
+    .xiangxia {
+      margin-bottom: 10rpx;
+    }
+  }
+}
+</style>

+ 208 - 0
src/packageEnter/pages/insurance/policyParticulars/index.vue

@@ -0,0 +1,208 @@
+<template>
+  <zj-page-container>
+    <zj-fiex-column
+      background="#F7F7F7"
+      @scrolltolower="carScrolltolower"
+      @refresherrefresh="carRefresherrefresh"
+      @refresherrestore="carRefresherrestore"
+      :refresherEnabled="true"
+      :refresherTriggered="refresherTriggered"
+    >
+      <view slot="before" class="head-view">
+        <view class="head-view-bg"></view>
+      </view>
+      <view class="page-content">
+        <view class="page-title-view">
+          <text>{{ info.policyName }}</text>
+          <image mode="aspectFit" src="/static/images/common/bpa.png"> </image>
+        </view>
+        <view class="page-content-view">
+          <view class="page-content-text">
+            <text class="mintext">保单名称:{{ info.policyName }}</text>
+          </view>
+          <view class="page-content-text">
+            <text class="mintext"
+              >保障期限:{{ info && info.startTime && info.startTime.split(' ')[0] }}至{{
+                info && info.endTime && info.endTime.split(' ')[0]
+              }}</text
+            >
+            <text class="ogtext minwidth"
+              >{{
+                parseInt(
+                  baozhang > 0
+                    ? baozhang === 1
+                      ? getDaysBetween(info.startTime, new Date())
+                      : getDaysBetween(info.startTime, info.endTime)
+                    : 0
+                )
+              }}天</text
+            >
+          </view>
+          <view class="page-content-text">
+            <text class="mintext">被保险人:{{ info.workerName || '' }}</text>
+          </view>
+          <view class="page-content-text">
+            <text class="mintext">所属网点:{{ info.websitName || '' }}</text>
+          </view>
+          <image
+            v-if="info.policyOrderStatus === 'DSX'"
+            class="yingzhang"
+            mode="aspectFit"
+            src="/static/images/common/dsx.png"
+          >
+          </image>
+          <image
+            v-if="info.policyOrderStatus === 'BZZ'"
+            class="yingzhang"
+            mode="aspectFit"
+            src="/static/images/common/yshx.png"
+          >
+          </image>
+          <image
+            v-if="info.policyOrderStatus === 'YSX'"
+            class="yingzhang"
+            mode="aspectFit"
+            src="/static/images/common/ysx.png"
+          >
+          </image>
+        </view>
+        <!-- --------------------- -->
+        <view class="page-content-view">
+          <view class="page-content-text">
+            <text class="bigtext">保障内容</text>
+          </view>
+          <view class="page-content-text">
+            <text class="mintext">保单编码:{{ info.policyOrderId }}</text>
+          </view>
+          <view class="page-content-text">
+            <text class="mintext">承保公司:{{ info.policy && info.policy.company }}</text>
+          </view>
+          <view class="hr" />
+          <view class="page-content-text">
+            <text class="bigtext">保障范围</text>
+          </view>
+          <view class="page-content-text" v-for="(item, index) in info.policyRanges || []" :key="index">
+            <text class="mintext">{{ item.rangeName }}</text>
+            <text class="mintext maxwidth">{{ item.rangeText }}</text>
+          </view>
+          <view class="hr" />
+          <view class="page-content-text">
+            <text class="bigtext">保费</text>
+            <text class="mintext">{{ info.payAmount }}</text>
+          </view>
+          <view class="page-content-text">
+            <text class="mintext">缴费方式</text>
+            <text class="mintext maxwidth">一次性年缴</text>
+          </view>
+          <view class="page-content-text">
+            <text class="tsogtext">注:已承保期间,不足一个月的部分按一个月计缴费</text>
+          </view>
+        </view>
+        <!-- --------------------- -->
+        <view class="page-content-view">
+          <view class="page-content-text">
+            <text class="bigtext">协议条款</text>
+          </view>
+          <template v-for="(item, index) in insureAgreeList">
+            <view class="page-content-text" :key="index" @click="goDetailsAgreement(item)">
+              <view class="baoxianxieyi">
+                <text>《{{ item.agreementName }}》</text>
+                <u-icon name="arrow-right" size="18"></u-icon>
+              </view>
+            </view>
+            <view class="minhr" v-if="index < insureAgreeList.length - 1" />
+          </template>
+        </view>
+        <u-button type="primary" plain @click="goHome">返回首页</u-button>
+      </view>
+    </zj-fiex-column>
+  </zj-page-container>
+</template>
+<script>
+import ZjFiexColumn from '@/components/zj-container/zj-fiex-column.vue'
+import ZjFiexRow from '@/components/zj-container/zj-fiex-row.vue'
+import ZjPageContainer from '@/components/zj-container/zj-page-container.vue'
+export default {
+  components: {
+    ZjFiexRow,
+    ZjFiexColumn,
+    ZjPageContainer
+  },
+  data() {
+    return {
+      info: {},
+      insureAgreeList: [],
+      refresherTriggered: false,
+      id: ''
+    }
+  },
+  computed: {
+    baozhang() {
+      return this.info.startTime && this.info.endTime ? this.isDuringDate(this.info.startTime, this.info.endTime) : -1
+    }
+  },
+  onLoad({ id }) {
+    this.id = id
+    this.redc()
+    uni.$emit('updateUserInfo')
+  },
+  methods: {
+    redc() {
+      this.$api.post('/worker/myDetail', { id: this.id }).then(res => {
+        console.log(res, '--')
+        this.info = res.data
+        this.insureAgreeList = res.data.agreements || []
+        this.refresherTriggered = false
+      })
+    },
+    getDaysBetween(date1, date2, a) {
+      var startDate = Date.parse(date1)
+      var endDate = Date.parse(date2)
+      if (startDate > endDate) {
+        return 0
+      }
+      if (startDate == endDate) {
+        return 1
+      }
+      var days = (endDate - startDate) / (1 * 24 * 60 * 60 * 1000)
+      return days
+    },
+    isDuringDate(beginDateStr, endDateStr) {
+      var curDate = new Date(),
+        beginDate = new Date(beginDateStr),
+        endDate = new Date(endDateStr)
+      if (curDate >= beginDate && curDate <= endDate) {
+        return 1
+      } else if (curDate < beginDate) {
+        return 0
+      } else if (curDate > endDate) {
+        return 2
+      }
+    },
+    goDetailsAgreement(item) {
+      if (item.id) {
+        uni.navigateTo({
+          url: `/packageEnter/pages/insurance/detailsAgreement/index?id=${item.id}`
+        })
+      }
+    },
+    // 滚动到底部
+    carScrolltolower(e) {},
+    // 触发下拉刷新
+    carRefresherrefresh(e) {
+      this.refresherTriggered = true
+      this.redc()
+    },
+    // 下拉刷新结束
+    carRefresherrestore(e) {},
+    goHome() {
+      uni.switchTab({
+        url: '/pages/index/index'
+      })
+    }
+  }
+}
+</script>
+<style lang="scss" scoped>
+@import './style.scss';
+</style>

+ 118 - 0
src/packageEnter/pages/insurance/policyParticulars/style.scss

@@ -0,0 +1,118 @@
+.head-view{
+	position: relative;
+	.head-view-bg{
+		position: absolute;
+		width: 100%;
+		height: 480rpx;
+		top: 0;
+		left: 0;
+		background: #3D8FFD;
+	}
+}
+.page-content {
+	min-height: 100%;
+	box-sizing: border-box;
+	padding: 30rpx;
+	.page-title-view{
+		width: 100%;
+		height: auto;
+		display: flex;
+		align-items: center;
+		margin-bottom: 40rpx;
+		text{
+			font-size: 48rpx;
+			font-family: Source Han Sans CN-Regular, Source Han Sans CN;
+			font-weight: 400;
+			color: #FFFFFF;
+		}
+		image{
+			width:160rpx;
+			height:48rpx;
+			margin-left:20rpx;
+		}
+	}
+	.page-content-view{
+		width: 100%;
+		box-sizing: border-box;
+		padding: 26rpx;
+		background: #FFFFFF;
+		border-radius: 20rpx;
+		position: relative;
+		&:not(:last-child){
+			margin-bottom: 20rpx;
+		}
+		.yingzhang{
+			width: 160rpx;
+			height: 160rpx;
+			position: absolute;
+			top: 70rpx;
+			right: 110rpx;
+		}
+		.baoxianxieyi{
+			width: 100%;
+			height: 70rpx;
+			display: flex;
+			justify-content: space-between;
+			align-items: center;
+			box-sizing: border-box;
+		}
+		.page-content-text{
+			width: 100%;
+			height: auto;
+			display: flex;
+			justify-content: space-between;
+			box-sizing: border-box;
+			padding: 5rpx 0;
+		}
+		.bigtext{
+			font-size: 32rpx;
+			font-family: Source Han Sans CN-Medium, Source Han Sans CN;
+			font-weight: 500;
+			color: #0B2853;
+			line-height: 40rpx;
+		}
+		.mintext{
+			font-size: 28rpx;
+			font-family: Source Han Sans CN-Regular, Source Han Sans CN;
+			font-weight: 400;
+			color: #87919F;
+			line-height: 40rpx;
+		}
+		.ogtext{
+			font-size: 40rpx;
+			font-family: Source Han Sans CN-Regular, Source Han Sans CN;
+			font-weight: 400;
+			color: #E95505;
+			line-height: 40rpx;
+		}
+		.tsogtext{
+			font-size: 24rpx;
+			font-family: Source Han Sans CN-Regular, Source Han Sans CN;
+			font-weight: 400;
+			color: #FE894A;
+			line-height: 40rpx;
+		}
+		.minwidth{
+			display: inline-block;
+			min-width: 130rpx;
+			text-align: right;
+			text-align: center;
+		}
+		.maxwidth{
+			display: inline-block;
+			max-width: 460rpx;
+		}
+		.hr{
+			width: 100%;
+			height: 1rpx;
+			background: #E5E5E5;
+			margin: 24rpx 0rpx;
+		}
+		.minhr{
+			width: 100%;
+			height: 1rpx;
+			background: #E5E5E5;
+		}
+	}
+	
+}

+ 52 - 0
src/pages.json

@@ -74,6 +74,58 @@
 
   "subpackages": [
     {
+      "root": "packageEnter",
+      "name": "packageEnter",
+      "pages": [
+        {
+          "path": "pages/insurance/myInsuranceBuy/index",
+          "style": {
+            "navigationBarTitleText": "购买保险",
+            "enablePullDownRefresh": true
+          }
+        },
+        {
+          "path": "pages/insurance/myInsurance/index",
+          "style": {
+            "navigationBarTitleText": "我的保险",
+            "enablePullDownRefresh": true
+          }
+        },
+        {
+          "path": "pages/insurance/insuranceContract/index",
+          "style": {
+            "navigationBarTitleText": "保险合同"
+          }
+        },
+        {
+          "path": "pages/insurance/determineInfo/index",
+          "style": {
+            "navigationBarTitleText": "确定信息"
+          }
+        },
+        {
+          "path": "pages/insurance/detailsAgreement/index",
+          "style": {
+            "navigationBarTitleText": ""
+          }
+        },
+        {
+          "path": "pages/insurance/insurancePolicy/index",
+          "style": {
+            "navigationBarTitleText": "保险单"
+          }
+        },
+        {
+          "path": "pages/insurance/policyParticulars/index",
+          "style": {
+            "navigationBarTitleText": "保单详情",
+            "navigationBarTextStyle": "#ffffff",
+            "navigationBarBackgroundColor": "#3D8FFD"
+          }
+        }
+      ]
+    },
+    {
       "root": "packageAttachment",
       "name": "packageAttachment",
       "pages": [

+ 6 - 0
src/pages/mine/index.vue

@@ -362,6 +362,12 @@ export default {
           icon: 'icon-kehu',
           link: '/packageMine/pages/masterGroup/index',
           show: true
+        },
+        {
+          name: '我的保单',
+          icon: 'icon-kehu',
+          link: '/packageEnter/pages/insurance/myInsurance/index',
+          show: true
         }
       ]
     },

BIN
src/static/images/common/bpa.png


BIN
src/static/images/common/dsx.png


BIN
src/static/images/common/qrcode.png


BIN
src/static/images/common/yshx.png


BIN
src/static/images/common/ysx.png


+ 258 - 0
src/utils/md5.js

@@ -0,0 +1,258 @@
+/*
+ * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
+ * Digest Algorithm, as defined in RFC 1321.
+ * Version 2.1 Copyright (C) Paul Johnston 1999 - 2002.
+ * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
+ * Distributed under the BSD License
+ * See http://pajhome.org.uk/crypt/md5 for more info.
+ */
+
+/*
+ * Configurable variables. You may need to tweak these to be compatible with
+ * the server-side, but the defaults work in most cases.
+ */
+var hexcase = 0 /* hex output format. 0 - lowercase; 1 - uppercase        */
+var b64pad = '' /* base-64 pad character. "=" for strict RFC compliance   */
+var chrsz = 8 /* bits per input character. 8 - ASCII; 16 - Unicode      */
+
+/*
+ * These are the functions you'll usually want to call
+ * They take string arguments and return either hex or base-64 encoded strings
+ */
+export function hex_md5(s) {
+  return binl2hex(core_md5(str2binl(s), s.length * chrsz))
+}
+
+export function b64_md5(s) {
+  return binl2b64(core_md5(str2binl(s), s.length * chrsz))
+}
+
+export function str_md5(s) {
+  return binl2str(core_md5(str2binl(s), s.length * chrsz))
+}
+
+export function hex_hmac_md5(key, data) {
+  return binl2hex(core_hmac_md5(key, data))
+}
+
+export function b64_hmac_md5(key, data) {
+  return binl2b64(core_hmac_md5(key, data))
+}
+
+export function str_hmac_md5(key, data) {
+  return binl2str(core_hmac_md5(key, data))
+}
+
+/*
+ * Perform a simple self-test to see if the VM is working
+ */
+function md5_vm_test() {
+  return hex_md5('abc') == '900150983cd24fb0d6963f7d28e17f72'
+}
+
+/*
+ * Calculate the MD5 of an array of little-endian words, and a bit length
+ */
+function core_md5(x, len) {
+  /* append padding */
+  x[len >> 5] |= 0x80 << len % 32
+  x[(((len + 64) >>> 9) << 4) + 14] = len
+
+  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 = md5_ff(a, b, c, d, x[i + 0], 7, -680876936)
+    d = md5_ff(d, a, b, c, x[i + 1], 12, -389564586)
+    c = md5_ff(c, d, a, b, x[i + 2], 17, 606105819)
+    b = md5_ff(b, c, d, a, x[i + 3], 22, -1044525330)
+    a = md5_ff(a, b, c, d, x[i + 4], 7, -176418897)
+    d = md5_ff(d, a, b, c, x[i + 5], 12, 1200080426)
+    c = md5_ff(c, d, a, b, x[i + 6], 17, -1473231341)
+    b = md5_ff(b, c, d, a, x[i + 7], 22, -45705983)
+    a = md5_ff(a, b, c, d, x[i + 8], 7, 1770035416)
+    d = md5_ff(d, a, b, c, x[i + 9], 12, -1958414417)
+    c = md5_ff(c, d, a, b, x[i + 10], 17, -42063)
+    b = md5_ff(b, c, d, a, x[i + 11], 22, -1990404162)
+    a = md5_ff(a, b, c, d, x[i + 12], 7, 1804603682)
+    d = md5_ff(d, a, b, c, x[i + 13], 12, -40341101)
+    c = md5_ff(c, d, a, b, x[i + 14], 17, -1502002290)
+    b = md5_ff(b, c, d, a, x[i + 15], 22, 1236535329)
+
+    a = md5_gg(a, b, c, d, x[i + 1], 5, -165796510)
+    d = md5_gg(d, a, b, c, x[i + 6], 9, -1069501632)
+    c = md5_gg(c, d, a, b, x[i + 11], 14, 643717713)
+    b = md5_gg(b, c, d, a, x[i + 0], 20, -373897302)
+    a = md5_gg(a, b, c, d, x[i + 5], 5, -701558691)
+    d = md5_gg(d, a, b, c, x[i + 10], 9, 38016083)
+    c = md5_gg(c, d, a, b, x[i + 15], 14, -660478335)
+    b = md5_gg(b, c, d, a, x[i + 4], 20, -405537848)
+    a = md5_gg(a, b, c, d, x[i + 9], 5, 568446438)
+    d = md5_gg(d, a, b, c, x[i + 14], 9, -1019803690)
+    c = md5_gg(c, d, a, b, x[i + 3], 14, -187363961)
+    b = md5_gg(b, c, d, a, x[i + 8], 20, 1163531501)
+    a = md5_gg(a, b, c, d, x[i + 13], 5, -1444681467)
+    d = md5_gg(d, a, b, c, x[i + 2], 9, -51403784)
+    c = md5_gg(c, d, a, b, x[i + 7], 14, 1735328473)
+    b = md5_gg(b, c, d, a, x[i + 12], 20, -1926607734)
+
+    a = md5_hh(a, b, c, d, x[i + 5], 4, -378558)
+    d = md5_hh(d, a, b, c, x[i + 8], 11, -2022574463)
+    c = md5_hh(c, d, a, b, x[i + 11], 16, 1839030562)
+    b = md5_hh(b, c, d, a, x[i + 14], 23, -35309556)
+    a = md5_hh(a, b, c, d, x[i + 1], 4, -1530992060)
+    d = md5_hh(d, a, b, c, x[i + 4], 11, 1272893353)
+    c = md5_hh(c, d, a, b, x[i + 7], 16, -155497632)
+    b = md5_hh(b, c, d, a, x[i + 10], 23, -1094730640)
+    a = md5_hh(a, b, c, d, x[i + 13], 4, 681279174)
+    d = md5_hh(d, a, b, c, x[i + 0], 11, -358537222)
+    c = md5_hh(c, d, a, b, x[i + 3], 16, -722521979)
+    b = md5_hh(b, c, d, a, x[i + 6], 23, 76029189)
+    a = md5_hh(a, b, c, d, x[i + 9], 4, -640364487)
+    d = md5_hh(d, a, b, c, x[i + 12], 11, -421815835)
+    c = md5_hh(c, d, a, b, x[i + 15], 16, 530742520)
+    b = md5_hh(b, c, d, a, x[i + 2], 23, -995338651)
+
+    a = md5_ii(a, b, c, d, x[i + 0], 6, -198630844)
+    d = md5_ii(d, a, b, c, x[i + 7], 10, 1126891415)
+    c = md5_ii(c, d, a, b, x[i + 14], 15, -1416354905)
+    b = md5_ii(b, c, d, a, x[i + 5], 21, -57434055)
+    a = md5_ii(a, b, c, d, x[i + 12], 6, 1700485571)
+    d = md5_ii(d, a, b, c, x[i + 3], 10, -1894986606)
+    c = md5_ii(c, d, a, b, x[i + 10], 15, -1051523)
+    b = md5_ii(b, c, d, a, x[i + 1], 21, -2054922799)
+    a = md5_ii(a, b, c, d, x[i + 8], 6, 1873313359)
+    d = md5_ii(d, a, b, c, x[i + 15], 10, -30611744)
+    c = md5_ii(c, d, a, b, x[i + 6], 15, -1560198380)
+    b = md5_ii(b, c, d, a, x[i + 13], 21, 1309151649)
+    a = md5_ii(a, b, c, d, x[i + 4], 6, -145523070)
+    d = md5_ii(d, a, b, c, x[i + 11], 10, -1120210379)
+    c = md5_ii(c, d, a, b, x[i + 2], 15, 718787259)
+    b = md5_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 Array(a, b, c, d)
+}
+
+/*
+ * These functions implement the four basic operations the algorithm uses.
+ */
+function md5_cmn(q, a, b, x, s, t) {
+  return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s), b)
+}
+
+function md5_ff(a, b, c, d, x, s, t) {
+  return md5_cmn((b & c) | (~b & d), a, b, x, s, t)
+}
+
+function md5_gg(a, b, c, d, x, s, t) {
+  return md5_cmn((b & d) | (c & ~d), a, b, x, s, t)
+}
+
+function md5_hh(a, b, c, d, x, s, t) {
+  return md5_cmn(b ^ c ^ d, a, b, x, s, t)
+}
+
+function md5_ii(a, b, c, d, x, s, t) {
+  return md5_cmn(c ^ (b | ~d), a, b, x, s, t)
+}
+
+/*
+ * Calculate the HMAC-MD5, of a key and some data
+ */
+function core_hmac_md5(key, data) {
+  var bkey = str2binl(key)
+  if (bkey.length > 16) bkey = core_md5(bkey, key.length * chrsz)
+
+  var ipad = Array(16),
+    opad = Array(16)
+  for (var i = 0; i < 16; i++) {
+    ipad[i] = bkey[i] ^ 0x36363636
+    opad[i] = bkey[i] ^ 0x5c5c5c5c
+  }
+
+  var hash = core_md5(ipad.concat(str2binl(data)), 512 + data.length * chrsz)
+  return core_md5(opad.concat(hash), 512 + 128)
+}
+
+/*
+ * 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 bit_rol(num, cnt) {
+  return (num << cnt) | (num >>> (32 - cnt))
+}
+
+/*
+ * Convert a string to an array of little-endian words
+ * If chrsz is ASCII, characters >255 have their hi-byte silently ignored.
+ */
+function str2binl(str) {
+  var bin = Array()
+  var mask = (1 << chrsz) - 1
+  for (var i = 0; i < str.length * chrsz; i += chrsz) bin[i >> 5] |= (str.charCodeAt(i / chrsz) & mask) << i % 32
+  return bin
+}
+
+/*
+ * Convert an array of little-endian words to a string
+ */
+function binl2str(bin) {
+  var str = ''
+  var mask = (1 << chrsz) - 1
+  for (var i = 0; i < bin.length * 32; i += chrsz) str += String.fromCharCode((bin[i >> 5] >>> i % 32) & mask)
+  return str
+}
+
+/*
+ * Convert an array of little-endian words to a hex string.
+ */
+function binl2hex(binarray) {
+  var hex_tab = hexcase ? '0123456789ABCDEF' : '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 base-64 string
+ */
+function binl2b64(binarray) {
+  var tab = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
+  var str = ''
+  for (var i = 0; i < binarray.length * 4; i += 3) {
+    var triplet =
+      (((binarray[i >> 2] >> (8 * (i % 4))) & 0xff) << 16) |
+      (((binarray[(i + 1) >> 2] >> (8 * ((i + 1) % 4))) & 0xff) << 8) |
+      ((binarray[(i + 2) >> 2] >> (8 * ((i + 2) % 4))) & 0xff)
+    for (var j = 0; j < 4; j++) {
+      if (i * 8 + j * 6 > binarray.length * 32) str += b64pad
+      else str += tab.charAt((triplet >> (6 * (3 - j))) & 0x3f)
+    }
+  }
+  return str
+}

+ 42 - 0
src/utils/tool.js

@@ -0,0 +1,42 @@
+/**
+ * 倒计时方法注册
+ */
+export function countdown(startFun, endFun, frequency, seconds = 1000) {
+  var s = 0
+  var bool = false
+  var timeId = null
+
+  function enjs() {
+    if (timeId) {
+      clearTimeout(timeId)
+    }
+    if (bool && endFun) {
+      bool = false
+      endFun()
+    }
+  }
+
+  function djs() {
+    timeId = setTimeout(function () {
+      s--
+      if (s <= 0) {
+        enjs()
+      } else {
+        startFun && startFun(s)
+        djs()
+      }
+    }, seconds)
+  }
+  return {
+    start() {
+      s = frequency
+      bool = true
+      startFun && startFun(s)
+      djs()
+    },
+    end() {
+      s = 0
+      enjs()
+    }
+  }
+}

+ 232 - 0
src/utils/utils.js

@@ -0,0 +1,232 @@
+
+/**
+ * 对象转URL
+ */
+export const urlEncode = function(data) {
+	var _result = [];
+	for (var key in data) {
+		var value = data[key];
+		if (value.constructor == Array) {
+			value.forEach(_value => {
+				_result.push(key + "=" + _value);
+			});
+		} else {
+			_result.push(key + '=' + value);
+		}
+	}
+	return _result.join('&');
+}
+
+/**
+  * scene解码
+*/
+export const scene_decode = function (e) {
+	if (e === undefined)
+		return {};
+	let scene = decodeURIComponent(e),
+		params = scene.split(','),
+		data = {};
+	for (let i in params) {
+		var val = params[i].split(':');
+		val.length > 0 && val[0] && (data[val[0]] = val[1] || null)
+	}
+	return data;
+}
+export const deepCopy = function (obj) {
+	//判断拷贝的要进行深拷贝的是数组还是对象,是数组的话进行数组拷贝,对象的话进行对象拷贝
+	var objClone = Array.isArray(obj) ? [] : {};
+	//进行深拷贝的不能为空,并且是对象或者是
+	if (obj && typeof obj === "object") {
+		for (var key in obj) {
+			if (obj.hasOwnProperty(key)) {
+				if (obj[key] && typeof obj[key] === "object") {
+					objClone[key] = deepCopy(obj[key]);
+				} else {
+					objClone[key] = obj[key];
+				}
+			}
+		}
+	}
+	return objClone;
+};
+/*
+@parmas current 页面栈,非必传,不传的时候默认返回上一页
+*/
+export const getPage = function (current) {
+	if (!current) {
+		current = 2;
+	}
+	var pages = getCurrentPages(),
+		length = pages.length,
+		page = pages[length - current];
+	return page
+};
+
+/*
+*时间戳转化日期方法
+*@params val 时间戳,必传;
+*@params type 转化类型,非必传,默认返回年月日加时间,等于ymd时,返回年月日,等于hms返回时间
+*/
+export const timeToDate = function (val,type) {
+	if(!val){
+		throw new Error('val ')
+	}
+	var date = new Date(val * 1000),
+		Y = date.getFullYear(),
+		M = date.getMonth() + 1,
+		D = date.getDate(),
+		H = date.getHours(),
+		m = date.getMinutes(),
+		s = date.getSeconds();
+	M = M < 10 ? '0' + M : M;
+	D = D < 10 ? '0' + D : D;
+	H = H < 10 ? '0' + H : H;
+	m = m < 10 ? '0' + m : m;
+	s = s < 10 ? '0' + s : s;
+	if(!type){
+		return `${Y}-${M}-${D} ${H}:${m}:${s}`
+	}else if(type === 'ymd'){
+		return `${Y}-${M}-${D}`
+	}else if(type === 'hms'){
+		return `${H}:${m}:${s}`
+	}
+
+};
+//支付统一处理方法
+export const payMoney = function (pay_info) {
+	return new Promise((resolve,reject)=>{
+		uni.requestPayment({
+			timeStamp: pay_info.timestamp,
+			nonceStr: pay_info.nonceStr,
+			package: pay_info.package,
+			signType: pay_info.signType,
+			paySign: pay_info.paySign,
+			success(res) {
+				resolve(res)
+			},
+			fail(err) {
+				reject(err)
+			}
+		})
+	})
+}
+export const hasLogin = function () {
+	return new Promise((resolve, reject) => {
+		uni.getSetting({
+			success(res) {
+				if (res.authSetting['scope.userInfo']) {
+					uni.getUserInfo({
+						success(res) {
+							console.log('我授权登陆过了')
+							resolve(res);
+						}
+					})
+				} else {
+					uni.hideLoading();
+					reject()
+				}
+			},
+			fail(err) {
+				reject(err)
+			}
+		})
+	})
+}
+/**
+ * 将时间戳转化为多久以前
+ * */
+export const changeTime = function(timestamp) {
+	let currentUnixTime = Math.round((new Date()).getTime() / 1000);
+	let deltaSecond = currentUnixTime - parseInt(timestamp, 10);
+	let result;
+	if (deltaSecond < 60) {
+		result = deltaSecond + '秒前';
+	} else if (deltaSecond < 3600) {
+		result = Math.floor(deltaSecond / 60) + '分钟前';
+	} else if (deltaSecond < 86400) {
+		result = Math.floor(deltaSecond / 3600) + '小时前';
+	} else {
+		result = Math.floor(deltaSecond / 86400) + '天前';
+	}
+	return result;
+}
+
+export const professTotal = function(val) {
+	if(!val)return 0;
+	if (val > 10000) {
+		return (val / 10000).toFixed(2) + '万'
+	} else {
+		return val
+	}
+}
+
+export const getArea = function(str) {
+	let area = {}
+	let index11 = 0
+	let index1 = str.indexOf("省")
+	if (index1 == -1) {
+	  index11 = str.indexOf("自治区")
+	  if (index11 != -1) {
+	    area.Province = str.substring(0, index11 + 3)
+	  } else {
+	    area.Province = str.substring(0, 0)
+	  }
+	} else {
+	  area.Province = str.substring(0, index1 + 1)
+	}
+				 
+	let index2 = str.indexOf("市")
+	if (index11 == -1) {
+	  area.City = str.substring(index11 + 1, index2 + 1)
+	} else {
+	  if (index11 == 0) {
+	    area.City = str.substring(index1 + 1, index2 + 1)
+	  } else {
+	    area.City = str.substring(index11 + 3, index2 + 1)
+	  }
+	}
+				 
+	let index3 = str.lastIndexOf("区")
+	if (index3 == -1) {
+	  index3 = str.indexOf("县")
+	  area.Country = str.substring(index2 + 1, index3 + 1)
+	} else {
+	  area.Country = str.substring(index2 + 1, index3 + 1)
+	}
+	return area;
+}
+
+/** 
+ * 比较时间是否在范围内
+ * @param {Object} stime
+ * @param {Object} etime
+ * @return {Boolean}
+ */
+export const compareTime = function(stime, etime) {
+	function tranDate(time) {
+		return new Date(time.replace(/-/g, '/')).getTime();
+	}
+	let startTime = tranDate(stime);
+	let endTime = tranDate(etime);
+	let nowTime = new Date().getTime();
+	
+	if(nowTime < startTime || nowTime > endTime) {
+		return false;
+	}
+	return true;
+}
+
+
+export default {
+	deepCopy,
+	getPage,
+	timeToDate,
+	payMoney,
+	scene_decode,
+	hasLogin,
+	urlEncode,
+	changeTime,
+	professTotal,
+	getArea,
+	compareTime
+}