初始化产品库
							
								
								
									
										174
									
								
								src/pages/app.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,174 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <section class="app">
 | 
			
		||||
    <u-swiper :list="list" height="240" bg-color="#408CFF"></u-swiper>
 | 
			
		||||
    <label class="useful-app">常用应用</label>
 | 
			
		||||
    <u-grid
 | 
			
		||||
      :col="o.length"
 | 
			
		||||
      :border="false"
 | 
			
		||||
      v-for="(o, i) in gridGroup"
 | 
			
		||||
      :key="i"
 | 
			
		||||
    >
 | 
			
		||||
      <u-grid-item v-for="(i, j) in o" :key="j" @click="linkTo(i)">
 | 
			
		||||
        <u-icon :name="i.icon" :size="100"></u-icon>
 | 
			
		||||
        <view class="grid-text">{{ i.label }}</view>
 | 
			
		||||
      </u-grid-item>
 | 
			
		||||
    </u-grid>
 | 
			
		||||
    <label class="useful-app notice">通知公告</label>
 | 
			
		||||
    <section class="list">
 | 
			
		||||
      <div class="item" v-for="(item, index) in dataList" :key="index">
 | 
			
		||||
        <label class="title hidden">{{ item.title }}</label>
 | 
			
		||||
        <div class="content hidden">{{ item.content }}</div>
 | 
			
		||||
        <div class="date">{{ item.createTime }}</div>
 | 
			
		||||
      </div>
 | 
			
		||||
      <u-loadmore :status="status" />
 | 
			
		||||
    </section>
 | 
			
		||||
  </section>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
export default {
 | 
			
		||||
  name: 'app',
 | 
			
		||||
  data() {
 | 
			
		||||
    return {
 | 
			
		||||
      list: [this.imgHomeUrl + 'banner.png'],
 | 
			
		||||
      gridGroup: [
 | 
			
		||||
        [
 | 
			
		||||
          {
 | 
			
		||||
            icon: `${this.imgHomeUrl}icon1.png`,
 | 
			
		||||
            label: '随心问',
 | 
			
		||||
            link: '/pages/casuallyask/casuallyask'
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            icon: `${this.imgHomeUrl}icon2.png`,
 | 
			
		||||
            label: '随手拍',
 | 
			
		||||
            link: '/pages/snapshot/snapshot'
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            icon: `${this.imgHomeUrl}icon3.png`,
 | 
			
		||||
            label: '网上办事',
 | 
			
		||||
            link: '/pages/workonline/workonline'
 | 
			
		||||
          },
 | 
			
		||||
          { icon: `${this.imgHomeUrl}icon4.png`, label: '调查走访' }
 | 
			
		||||
        ],
 | 
			
		||||
        [
 | 
			
		||||
          {
 | 
			
		||||
            icon: `${this.imgHomeUrl}icon5.png`,
 | 
			
		||||
            label: '信用好超市',
 | 
			
		||||
            link: '/pages/supermarket/supermarket'
 | 
			
		||||
          },
 | 
			
		||||
          { icon: `${this.imgHomeUrl}icon6.png`, label: '中心工作' },
 | 
			
		||||
          { icon: `${this.imgHomeUrl}icon7.png`, label: '会务通知' },
 | 
			
		||||
          { icon: `${this.imgHomeUrl}icon8.png`, label: '工作去向' },
 | 
			
		||||
          { icon: `${this.imgHomeUrl}icon8.png`, label: '大喇叭' }
 | 
			
		||||
        ]
 | 
			
		||||
      ],
 | 
			
		||||
      status: 'nomore',
 | 
			
		||||
      dataList: [],
 | 
			
		||||
      current: 0
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  onLoad() {
 | 
			
		||||
    this.getList()
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    getList() {
 | 
			
		||||
      if (this.loadingStatus == 'nomore') return
 | 
			
		||||
      this.$http
 | 
			
		||||
        .post(`/app/appworkcenternotice/list`, null, {
 | 
			
		||||
          params: {
 | 
			
		||||
            withoutToken: true,
 | 
			
		||||
            current: this.current + 1,
 | 
			
		||||
            size: 10
 | 
			
		||||
          }
 | 
			
		||||
        })
 | 
			
		||||
        .then(res => {
 | 
			
		||||
          if (res && res.data) {
 | 
			
		||||
            this.dataList = res.data.records
 | 
			
		||||
          }
 | 
			
		||||
        })
 | 
			
		||||
    },
 | 
			
		||||
    linkTo(val) {
 | 
			
		||||
      if (val.link) {
 | 
			
		||||
        uni.navigateTo({ url: val.link })
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  onReachBottom() {
 | 
			
		||||
    this.getList()
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
.app {
 | 
			
		||||
  min-height: 100%;
 | 
			
		||||
  background-color: #ffffff;
 | 
			
		||||
  box-sizing: border-box;
 | 
			
		||||
  padding: 32px;
 | 
			
		||||
  position: relative;
 | 
			
		||||
 | 
			
		||||
  .grid-text {
 | 
			
		||||
    font-size: 28px;
 | 
			
		||||
    color: #333333;
 | 
			
		||||
    line-height: 46px;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .useful-app {
 | 
			
		||||
    margin-top: 80px;
 | 
			
		||||
    display: inherit;
 | 
			
		||||
    font-size: 36px;
 | 
			
		||||
    font-weight: bold;
 | 
			
		||||
    color: #333333;
 | 
			
		||||
    line-height: 50px;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .notice {
 | 
			
		||||
    margin-top: 56px;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .list {
 | 
			
		||||
    margin-top: 38px;
 | 
			
		||||
 | 
			
		||||
    .item {
 | 
			
		||||
      height: 192px;
 | 
			
		||||
      background: #f7f9ff;
 | 
			
		||||
      border-radius: 8px;
 | 
			
		||||
      box-sizing: border-box;
 | 
			
		||||
      padding: 20px;
 | 
			
		||||
      margin-bottom: 32px;
 | 
			
		||||
 | 
			
		||||
      .title {
 | 
			
		||||
        font-size: 32px;
 | 
			
		||||
        font-weight: 800;
 | 
			
		||||
        color: #343d65;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .content {
 | 
			
		||||
        font-size: 28px;
 | 
			
		||||
        color: #333333;
 | 
			
		||||
        font-weight: 500;
 | 
			
		||||
        margin: 20px 0 8px 0;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .date {
 | 
			
		||||
        font-size: 28px;
 | 
			
		||||
        color: #666666;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .hidden {
 | 
			
		||||
    overflow: hidden;
 | 
			
		||||
    text-overflow: ellipsis;
 | 
			
		||||
    white-space: nowrap;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ::v-deep .u-indicator-item-round {
 | 
			
		||||
    background-color: #d8dde6;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ::v-deep .u-indicator-item-round-active {
 | 
			
		||||
    background-color: #408cff !important;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										700
									
								
								src/pages/askForm/addForm.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,700 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="add-form" v-if="pageShow">
 | 
			
		||||
    <div class="header-pic">
 | 
			
		||||
      <image v-if="form.headPicture" :src="form.headPicture" />
 | 
			
		||||
      <span @click="upload">更换图片</span>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="form-info">
 | 
			
		||||
      <h2>文本选项</h2>
 | 
			
		||||
      <div class="form-info__wrapper">
 | 
			
		||||
        <textarea class="title" placeholder="请输入标题 (必填)" :maxlength="30" :auto-height="true" v-model="form.title"></textarea>
 | 
			
		||||
        <u-input class="content" :clearable="false" type="textarea" v-model="form.tableExplain" placeholder="请输入表单描述 (选填)" :height="80" :auto-height="true" :maxlength="255"></u-input>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <draggable
 | 
			
		||||
      class="components-list"
 | 
			
		||||
      v-model="targetList"
 | 
			
		||||
      :animation="340"
 | 
			
		||||
      scroll
 | 
			
		||||
      element="div"
 | 
			
		||||
      :options="{
 | 
			
		||||
        animation: 340,
 | 
			
		||||
        handle: '.components-item__title'
 | 
			
		||||
      }"
 | 
			
		||||
      draggable=".components-item"
 | 
			
		||||
      :sort="true">
 | 
			
		||||
      <div class="components-item" v-for="(item, index) in targetList" :key="index" @click="toFiledSetting(item, index)">
 | 
			
		||||
        <div class="components-item__title">
 | 
			
		||||
          <div class="components-item__title--left">
 | 
			
		||||
            <em :style="{opacity: item.required ? 1 : 0}">*</em>
 | 
			
		||||
            <i>{{ index + 1 }}.</i>
 | 
			
		||||
            <h2>{{ item.label }}</h2>
 | 
			
		||||
          </div>
 | 
			
		||||
          <image :src="`${$cdn}askform/sc1.png`" @click.stop="removeComponent(index)" @touchstart.stop="removeComponent(index)" />
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="components-item__filed">
 | 
			
		||||
          <template v-if="(item.type === 'radio')">
 | 
			
		||||
            <u-radio-group v-model="item.value" wrap>
 | 
			
		||||
              <u-radio disabled :name="field.label" v-for="(field, i) in item.options" :key="i">
 | 
			
		||||
                <image :src="field.img[0].url" v-if="field.img.length"/>
 | 
			
		||||
                <span>{{ field.label }}</span>
 | 
			
		||||
              </u-radio>
 | 
			
		||||
            </u-radio-group>
 | 
			
		||||
          </template>
 | 
			
		||||
          <template v-if="(item.type === 'checkbox')">
 | 
			
		||||
            <u-checkbox-group v-model="item.value" wrap>
 | 
			
		||||
              <u-checkbox  disabled :name="field.label" v-for="(field, i) in item.options" :key="i">
 | 
			
		||||
                <image :src="field.img[0].url" v-if="field.img.length"/>
 | 
			
		||||
                <span>{{ field.label }}</span>
 | 
			
		||||
              </u-checkbox>
 | 
			
		||||
            </u-checkbox-group>
 | 
			
		||||
          </template>
 | 
			
		||||
          <template v-if="(item.type === 'select')">
 | 
			
		||||
            <div class="components-item__select">
 | 
			
		||||
              <span>{{ item.placeholder }}</span>
 | 
			
		||||
              <u-icon name="arrow-down" color="#DEDFDF" />
 | 
			
		||||
            </div>
 | 
			
		||||
          </template>
 | 
			
		||||
          <template v-if="(item.type === 'upload')">
 | 
			
		||||
            <div class="components-item__select components-item__textarea components-item__upload">
 | 
			
		||||
              <image :src="`${$cdn}askform/upload.png`" />
 | 
			
		||||
              <span>选择图片(2M以内)</span>
 | 
			
		||||
            </div>
 | 
			
		||||
          </template>
 | 
			
		||||
          <template v-if="(item.type === 'input')">
 | 
			
		||||
            <div class="components-item__select">
 | 
			
		||||
              <span>{{ item.placeholder }}</span>
 | 
			
		||||
            </div>
 | 
			
		||||
          </template>
 | 
			
		||||
          <template v-if="(item.type === 'textarea')">
 | 
			
		||||
            <div class="components-item__select components-item__textarea">
 | 
			
		||||
              <span>{{ item.placeholder }}</span>
 | 
			
		||||
            </div>
 | 
			
		||||
          </template>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </draggable>
 | 
			
		||||
    <div class="add-form__btn" @click="isShow = true">
 | 
			
		||||
      <image :src="`${$cdn}askform/add.png`" />
 | 
			
		||||
      <span>添加问题</span>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="add-form__footer">
 | 
			
		||||
      <div>
 | 
			
		||||
        <span @click="toPreview">预览</span>
 | 
			
		||||
        <span @click="toSetting">设置</span>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div @click="onConfirm">立即发布</div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <u-popup v-model="isShow" :closeable="false" mode="bottom">
 | 
			
		||||
      <div class="add-popup">
 | 
			
		||||
        <div class="add-popup__title">
 | 
			
		||||
          <h2>添加问题</h2>
 | 
			
		||||
          <image :src="`${$cdn}askform/zk.png`" mode="aspectFit" @click="isShow = false" />
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="add-popup__list">
 | 
			
		||||
          <span @click="toFiledSetting('radio')">单选题</span>
 | 
			
		||||
          <span @click="toFiledSetting('checkbox')">多选题</span>
 | 
			
		||||
          <span @click="toFiledSetting('select')">单下拉框</span>
 | 
			
		||||
          <span @click="toFiledSetting('input')">单行填空</span>
 | 
			
		||||
          <span @click="toFiledSetting('textarea')">多行填空</span>
 | 
			
		||||
          <span @click="toFiledSetting('upload')">上传图片</span>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </u-popup>
 | 
			
		||||
    <AiBack></AiBack>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
  import AiBack from "@/components/AiBack";
 | 
			
		||||
  import draggable from 'vuedraggable'
 | 
			
		||||
  export default {
 | 
			
		||||
    data () {
 | 
			
		||||
      return {
 | 
			
		||||
        pageShow: false,
 | 
			
		||||
        form: {
 | 
			
		||||
          tableExplain: '详细描述',
 | 
			
		||||
          title: '问卷调查',
 | 
			
		||||
          isShowheadPicture: true,
 | 
			
		||||
          isShowTableExplain: true,
 | 
			
		||||
          isShowBtn: true,
 | 
			
		||||
          headPicture: '',
 | 
			
		||||
          commitType: '1',
 | 
			
		||||
          periodValidityType: '0',
 | 
			
		||||
          actionNotice: '1',
 | 
			
		||||
          dynamicNotice: '1',
 | 
			
		||||
          periodValidityEndTime: '',
 | 
			
		||||
          shareStatus: '0',
 | 
			
		||||
          count: 0,
 | 
			
		||||
          wechatId: '0',
 | 
			
		||||
          type: 0,
 | 
			
		||||
          buttonExplain: '提交',
 | 
			
		||||
          tips: true
 | 
			
		||||
        },
 | 
			
		||||
        templateType: 0,
 | 
			
		||||
        targetList: [],
 | 
			
		||||
        isShow: false,
 | 
			
		||||
        type: 0,
 | 
			
		||||
        id: '',
 | 
			
		||||
        isQuote: false,
 | 
			
		||||
        touchStart: 0,
 | 
			
		||||
        formConfig: {}
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    components: {
 | 
			
		||||
      AiBack,
 | 
			
		||||
      draggable
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    onLoad (query) {
 | 
			
		||||
      this.type = Number(query.type)
 | 
			
		||||
 | 
			
		||||
      if (query.isQuote) {
 | 
			
		||||
        this.isQuote = true
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (query.id) {
 | 
			
		||||
        this.id = query.id
 | 
			
		||||
        this.getInfo(query.id)
 | 
			
		||||
      } else {
 | 
			
		||||
        this.pageShow = true
 | 
			
		||||
      }
 | 
			
		||||
      this.init()
 | 
			
		||||
 | 
			
		||||
      uni.$on('setting', res => {
 | 
			
		||||
        this.form = {
 | 
			
		||||
          ...this.form,
 | 
			
		||||
          ...res
 | 
			
		||||
        }
 | 
			
		||||
        this.formConfig = res
 | 
			
		||||
      })
 | 
			
		||||
 | 
			
		||||
      uni.$on('filedConfig', res => {
 | 
			
		||||
        if (res.index === '-1') {
 | 
			
		||||
          this.targetList.push(res.config)
 | 
			
		||||
        } else {
 | 
			
		||||
          this.$set(this.targetList, [res.index], res.config)
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    methods: {
 | 
			
		||||
      toSetting () {
 | 
			
		||||
        uni.navigateTo({
 | 
			
		||||
          url: `/pages/askForm/formSetting?id=${this.id}&formConfig=${JSON.stringify(this.formConfig)}`
 | 
			
		||||
        })
 | 
			
		||||
      },
 | 
			
		||||
 | 
			
		||||
      removeComponent (index) {
 | 
			
		||||
        this.targetList.splice(index, 1)
 | 
			
		||||
      },
 | 
			
		||||
 | 
			
		||||
      toPreview () {
 | 
			
		||||
        uni.navigateTo({
 | 
			
		||||
          url: `/pages/askForm/previewForm?targetList=${JSON.stringify(this.targetList)}&form=${JSON.stringify(this.form)}`
 | 
			
		||||
        })
 | 
			
		||||
      },
 | 
			
		||||
 | 
			
		||||
      upload() {
 | 
			
		||||
        let params = {
 | 
			
		||||
          count: 1,
 | 
			
		||||
          sizeType: ['compressed'],
 | 
			
		||||
          sourceType: ['album', 'camera'],
 | 
			
		||||
          success: (res) => {
 | 
			
		||||
            let count = this.fileList?.length + (res.tempFiles?.length || res.tempFile ? 1 : 0)
 | 
			
		||||
            if (count > 1) {
 | 
			
		||||
              return this.$u.toast(`不能超过1个`)
 | 
			
		||||
            }
 | 
			
		||||
            if (res.tempFiles) {
 | 
			
		||||
              res.tempFiles.map((item) => {
 | 
			
		||||
                this.uploadFile(item)
 | 
			
		||||
              })
 | 
			
		||||
            } else if (res?.tempFile) {
 | 
			
		||||
              this.uploadFile(res.tempFile)
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
        uni.chooseImage(params)
 | 
			
		||||
      },
 | 
			
		||||
 | 
			
		||||
      uploadFile (img) {
 | 
			
		||||
        uni.showLoading({title: '上传中'})
 | 
			
		||||
        let formData = new FormData()
 | 
			
		||||
        formData.append('file', img)
 | 
			
		||||
        this.$http.post('/admin/file/add2', formData).then((res) => {
 | 
			
		||||
          uni.hideLoading()
 | 
			
		||||
          if (res?.data) {
 | 
			
		||||
            this.$u.toast('上传成功!')
 | 
			
		||||
            this.form.headPicture = res.data.url
 | 
			
		||||
          }
 | 
			
		||||
        }).catch(res => {
 | 
			
		||||
          this.$u.toast(res)
 | 
			
		||||
          uni.hideLoading()
 | 
			
		||||
        })
 | 
			
		||||
      },
 | 
			
		||||
 | 
			
		||||
      onConfirm () {
 | 
			
		||||
        for (let item of this.targetList) {
 | 
			
		||||
          if (item.isShowPoints) {
 | 
			
		||||
            if (item.pointType === '0') {
 | 
			
		||||
              if (!item.answer || JSON.stringify(item.answer) === '[]') {
 | 
			
		||||
                return this.$u.toast(`请输入${item.label}正确答案`)
 | 
			
		||||
              }
 | 
			
		||||
 | 
			
		||||
              if (!item.points) {
 | 
			
		||||
                return this.$u.toast(`请输入${item.label}的分值`)
 | 
			
		||||
              }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (item.pointType === '1') {
 | 
			
		||||
              for (let option of item.options) {
 | 
			
		||||
                if (!option.point) {
 | 
			
		||||
                  return this.$u.toast(`请输入${item.label}${option.label}的分值`)
 | 
			
		||||
                }
 | 
			
		||||
              }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (item.pointType === '2') {
 | 
			
		||||
              for (let option of item.options) {
 | 
			
		||||
                if (!option.point) {
 | 
			
		||||
                  return this.$u.toast(`请输入${item.label}${option.label}的分值`)
 | 
			
		||||
                }
 | 
			
		||||
              }
 | 
			
		||||
 | 
			
		||||
              if (!item.points) {
 | 
			
		||||
                return this.$u.toast(`请输入${item.label}全部答对分值`)
 | 
			
		||||
              }
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const fields = this.targetList.map(item => {
 | 
			
		||||
          return {
 | 
			
		||||
            fieldType: item.type,
 | 
			
		||||
            fieldName: item.label,
 | 
			
		||||
            fieldInfo: JSON.stringify(item)
 | 
			
		||||
          }
 | 
			
		||||
        })
 | 
			
		||||
 | 
			
		||||
        this.$http.post(`/app/appquestionnairetemplate/addOrUpdate`, {
 | 
			
		||||
          ...this.form,
 | 
			
		||||
          fields,
 | 
			
		||||
          status: 1,
 | 
			
		||||
          id: this.isQuote ? '' : this.id,
 | 
			
		||||
          headPicture: this.form.headPicture,
 | 
			
		||||
          type: this.type,
 | 
			
		||||
          templateType: 0
 | 
			
		||||
        }).then(res => {
 | 
			
		||||
          if (res.code == 0) {
 | 
			
		||||
            this.$u.toast('提交成功')
 | 
			
		||||
 | 
			
		||||
            setTimeout(() => {
 | 
			
		||||
              uni.$emit('reload')
 | 
			
		||||
              uni.navigateBack({
 | 
			
		||||
                delta: 1
 | 
			
		||||
              })
 | 
			
		||||
            }, 600)
 | 
			
		||||
          }
 | 
			
		||||
        }).catch(e => {
 | 
			
		||||
          this.$u.toast(e)
 | 
			
		||||
        })
 | 
			
		||||
      },
 | 
			
		||||
 | 
			
		||||
      getInfo (id) {
 | 
			
		||||
        uni.showLoading()
 | 
			
		||||
        this.$http.post(`/app/appquestionnairetemplate/queryDetailById?id=${id}`).then(res => {
 | 
			
		||||
          if (res.code == 0) {
 | 
			
		||||
            this.form = {
 | 
			
		||||
              ...res.data,
 | 
			
		||||
              headPicture: res.data.headPicture
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            this.type = res.data.type
 | 
			
		||||
 | 
			
		||||
            this.targetList = res.data.fields.map(item => {
 | 
			
		||||
              return JSON.parse(item.fieldInfo)
 | 
			
		||||
            })
 | 
			
		||||
 | 
			
		||||
            this.pageShow = true
 | 
			
		||||
          } else {
 | 
			
		||||
            this.$u.toast(res.msg)
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          uni.hideLoading()
 | 
			
		||||
        }).catch(() => {
 | 
			
		||||
          uni.hideLoading()
 | 
			
		||||
        })
 | 
			
		||||
      },
 | 
			
		||||
 | 
			
		||||
      toFiledSetting (type, index) {
 | 
			
		||||
        if (index != undefined) {
 | 
			
		||||
          uni.navigateTo({
 | 
			
		||||
            url: `/pages/askForm/filedConfig?config=${JSON.stringify(type)}&index=${index}`
 | 
			
		||||
          })
 | 
			
		||||
 | 
			
		||||
          return false
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.isShow = false
 | 
			
		||||
        uni.navigateTo({
 | 
			
		||||
          url: `/pages/askForm/filedConfig?type=${type}`
 | 
			
		||||
        })
 | 
			
		||||
      },
 | 
			
		||||
 | 
			
		||||
      init () {
 | 
			
		||||
        if (this.type == 0) {
 | 
			
		||||
          this.form.headPicture = 'https://cdn.cunwuyun.cn/dvcp/h5/form/interview.png'
 | 
			
		||||
        }
 | 
			
		||||
        if (this.type == 1) {
 | 
			
		||||
          this.form.title = '考试测评'
 | 
			
		||||
          this.form.headPicture = 'https://cdn.cunwuyun.cn/dvcp/h5/form/exam.png'
 | 
			
		||||
        }
 | 
			
		||||
        if (this.type == 2) {
 | 
			
		||||
          this.form.title = '报名登记'
 | 
			
		||||
          this.form.headPicture = 'https://cdn.cunwuyun.cn/dvcp/h5/form/apply.png'
 | 
			
		||||
        }
 | 
			
		||||
        if (this.type == 3) {
 | 
			
		||||
          this.form.title = '满意调查'
 | 
			
		||||
          this.form.headPicture = 'https://cdn.cunwuyun.cn/dvcp/h5/form/satisfaction.png'
 | 
			
		||||
        }
 | 
			
		||||
        if (this.type == 4) {
 | 
			
		||||
          this.form.title = '投票评选'
 | 
			
		||||
          this.form.headPicture = 'https://cdn.cunwuyun.cn/dvcp/h5/form/vote.png'
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
  .add-form {
 | 
			
		||||
    min-height: 100vh;
 | 
			
		||||
    padding-bottom: 140px;
 | 
			
		||||
    box-sizing: border-box;
 | 
			
		||||
    background: #F3F6F9;
 | 
			
		||||
 | 
			
		||||
    * {
 | 
			
		||||
      box-sizing: border-box;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ::v-deep .u-drawer-bottom {
 | 
			
		||||
      background-color: transparent;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .components-list {
 | 
			
		||||
      padding: 0 20px;
 | 
			
		||||
 | 
			
		||||
      .components-item {
 | 
			
		||||
        margin-top: 24px;
 | 
			
		||||
        padding: 32px;
 | 
			
		||||
        box-shadow: 0 4px 8px 4px rgba(233, 233, 233, 0.39);
 | 
			
		||||
        border-radius: 8px;
 | 
			
		||||
        overflow: hidden;
 | 
			
		||||
        border: 1px solid #EEEFF0;
 | 
			
		||||
        background: #fff;
 | 
			
		||||
 | 
			
		||||
        ::v-deep .u-radio, ::v-deep .u-checkbox {
 | 
			
		||||
          position: relative;
 | 
			
		||||
          margin-bottom: 20px;
 | 
			
		||||
 | 
			
		||||
          &:last-child {
 | 
			
		||||
            margin-bottom: 0;
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          .u-checkbox__icon-wrap, .u-radio__icon-wrap {
 | 
			
		||||
            position: absolute;
 | 
			
		||||
            top: 4rpx;
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          .u-radio__label, .u-checkbox__label {
 | 
			
		||||
            display: flex;
 | 
			
		||||
            align-items: center;
 | 
			
		||||
            margin-right: 0;
 | 
			
		||||
            margin-left: 40px;
 | 
			
		||||
            text-align: justify;
 | 
			
		||||
 | 
			
		||||
            span {
 | 
			
		||||
              line-height: 1.5;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            image {
 | 
			
		||||
              width: 100px;
 | 
			
		||||
              height: 100px;
 | 
			
		||||
              margin: 0 10px;
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
        span {
 | 
			
		||||
          flex: 1;
 | 
			
		||||
          color: #666;
 | 
			
		||||
          font-size: 26px;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .components-item__select {
 | 
			
		||||
          display: flex;
 | 
			
		||||
          align-items: center;
 | 
			
		||||
          justify-content: space-between;
 | 
			
		||||
          width: 100%;
 | 
			
		||||
          height: 80px;
 | 
			
		||||
          margin-bottom: 8px;
 | 
			
		||||
          padding: 0 26px;
 | 
			
		||||
          border: 1px solid #DEDFDF;
 | 
			
		||||
 | 
			
		||||
          &.components-item__textarea {
 | 
			
		||||
            align-items: flex-start;
 | 
			
		||||
            height: 160px;
 | 
			
		||||
            padding-top: 20px;
 | 
			
		||||
 | 
			
		||||
            image {
 | 
			
		||||
              width: 46px;
 | 
			
		||||
              height: 34px;
 | 
			
		||||
              margin-right: 16px;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            span {
 | 
			
		||||
              color: #666;
 | 
			
		||||
              font-size: 26px;
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          &.components-item__upload {
 | 
			
		||||
            justify-content: center;
 | 
			
		||||
            align-items: center;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .components-item__title {
 | 
			
		||||
          display: flex;
 | 
			
		||||
          align-items: center;
 | 
			
		||||
          justify-content: space-between;
 | 
			
		||||
          margin-bottom: 32px;
 | 
			
		||||
 | 
			
		||||
          em {
 | 
			
		||||
            margin-right: 4px;
 | 
			
		||||
            font-style: normal;
 | 
			
		||||
            color: rgb(226, 33, 32);;
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          image {
 | 
			
		||||
            position: relative;
 | 
			
		||||
            flex-shrink: 1;
 | 
			
		||||
            right: -20px;
 | 
			
		||||
            width: 32px;
 | 
			
		||||
            height: 32px;
 | 
			
		||||
            box-sizing: content-box;
 | 
			
		||||
            padding: 30px 20px 30px 20px;
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          div {
 | 
			
		||||
            display: flex;
 | 
			
		||||
            align-items: baseline;
 | 
			
		||||
            max-width: 550px;
 | 
			
		||||
            color: #333333;
 | 
			
		||||
            font-size: 32px;
 | 
			
		||||
 | 
			
		||||
            i {
 | 
			
		||||
              font-style: normal;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            h2 {
 | 
			
		||||
              font-weight: 600;
 | 
			
		||||
              font-size: 32px;
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .add-popup {
 | 
			
		||||
      height: 440px;
 | 
			
		||||
      border-radius: 20px 20px 0 0;
 | 
			
		||||
      background: #fff;
 | 
			
		||||
 | 
			
		||||
      .add-popup__title {
 | 
			
		||||
        display: flex;
 | 
			
		||||
        position: relative;
 | 
			
		||||
        align-items: center;
 | 
			
		||||
        justify-content: center;
 | 
			
		||||
        height: 96px;
 | 
			
		||||
        border-bottom: 1px solid #E4E5E6;
 | 
			
		||||
 | 
			
		||||
        h2 {
 | 
			
		||||
          color: #333333;
 | 
			
		||||
          font-size: 32px;
 | 
			
		||||
          font-weight: 600;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        image {
 | 
			
		||||
          position: absolute;
 | 
			
		||||
          right: 32px;
 | 
			
		||||
          top: 50%;
 | 
			
		||||
          width: 30px;
 | 
			
		||||
          height: 20px;
 | 
			
		||||
          transform: translateY(-50%);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .add-popup__list {
 | 
			
		||||
        display: flex;
 | 
			
		||||
        flex-wrap: wrap;
 | 
			
		||||
        padding: 0 34px;
 | 
			
		||||
 | 
			
		||||
        span {
 | 
			
		||||
          width: calc((100% - 64px) / 3);
 | 
			
		||||
          height: 78px;
 | 
			
		||||
          line-height: 78px;
 | 
			
		||||
          margin-top: 32px;
 | 
			
		||||
          margin-right: 32px;
 | 
			
		||||
          text-align: center;
 | 
			
		||||
          color: #333333;
 | 
			
		||||
          font-size: 28px;
 | 
			
		||||
          border-radius: 8px;
 | 
			
		||||
          border: 1px solid #E4E5E6;
 | 
			
		||||
 | 
			
		||||
          &:nth-of-type(3n) {
 | 
			
		||||
            margin-right: 0;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .add-form__footer {
 | 
			
		||||
      display: flex;
 | 
			
		||||
      align-items: center;
 | 
			
		||||
      position: fixed;
 | 
			
		||||
      left: 0;
 | 
			
		||||
      bottom: 0;
 | 
			
		||||
      z-index: 1;
 | 
			
		||||
      width: 100%;
 | 
			
		||||
      height: 112px;
 | 
			
		||||
      text-align: center;
 | 
			
		||||
 | 
			
		||||
      div {
 | 
			
		||||
        display: flex;
 | 
			
		||||
        align-items: center;
 | 
			
		||||
        justify-content: center;
 | 
			
		||||
        flex: 1;
 | 
			
		||||
        height: 100%;
 | 
			
		||||
        text-align: center;
 | 
			
		||||
        background: #fff;
 | 
			
		||||
 | 
			
		||||
        &:last-child {
 | 
			
		||||
          color: #fff;
 | 
			
		||||
          font-size: 36px;
 | 
			
		||||
          background: #3192F4;
 | 
			
		||||
 | 
			
		||||
          &:active {
 | 
			
		||||
            opacity: 0.8;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        span {
 | 
			
		||||
          flex: 1;
 | 
			
		||||
          height: 100%;
 | 
			
		||||
          line-height: 112px;
 | 
			
		||||
          color: #333333;
 | 
			
		||||
          font-size: 32px;
 | 
			
		||||
 | 
			
		||||
          &:active {
 | 
			
		||||
            background: #eee;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .add-form__btn {
 | 
			
		||||
      display: flex;
 | 
			
		||||
      align-items: center;
 | 
			
		||||
      justify-content: center;
 | 
			
		||||
      width: 214px;
 | 
			
		||||
      height: 66px;
 | 
			
		||||
      line-height: 66px;
 | 
			
		||||
      margin: 64px auto 0;
 | 
			
		||||
      background: #FFFFFF;
 | 
			
		||||
      border-radius: 34px;
 | 
			
		||||
 | 
			
		||||
      &:active {
 | 
			
		||||
        opacity: 0.8;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      image {
 | 
			
		||||
        width: 28px;
 | 
			
		||||
        height: 28px;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      span {
 | 
			
		||||
        margin-left: 16px;
 | 
			
		||||
        color: #4392E6;
 | 
			
		||||
        font-size: 28px;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    * {
 | 
			
		||||
      box-sizing: border-box;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .form-info {
 | 
			
		||||
      padding: 0 20px;
 | 
			
		||||
 | 
			
		||||
      & > h2 {
 | 
			
		||||
        height: 76px;
 | 
			
		||||
        line-height: 76px;
 | 
			
		||||
        color: #999999;
 | 
			
		||||
        font-weight: normal;
 | 
			
		||||
        font-size: 28px;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .form-info__wrapper {
 | 
			
		||||
        padding: 0 18px;
 | 
			
		||||
        background: #fff;
 | 
			
		||||
 | 
			
		||||
        .title {
 | 
			
		||||
          width: 100%;
 | 
			
		||||
          padding: 22px 0;
 | 
			
		||||
          font-size: 36px;
 | 
			
		||||
          border-bottom: 1px solid #F1F2F3;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .content {
 | 
			
		||||
          padding: 30px 0!important;
 | 
			
		||||
          font-size: 28px;
 | 
			
		||||
 | 
			
		||||
          ::v-deep textarea {
 | 
			
		||||
            color: #333;
 | 
			
		||||
            font-size: 28px!important;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .header-pic {
 | 
			
		||||
      position: relative;
 | 
			
		||||
      font-size: 0;
 | 
			
		||||
 | 
			
		||||
      span {
 | 
			
		||||
        position: absolute;
 | 
			
		||||
        bottom: 16px;
 | 
			
		||||
        right: 16px;
 | 
			
		||||
        z-index: 1;
 | 
			
		||||
        width: 148px;
 | 
			
		||||
        height: 56px;
 | 
			
		||||
        line-height: 56px;
 | 
			
		||||
        text-align: center;
 | 
			
		||||
        color: #fff;
 | 
			
		||||
        font-size: 26px;
 | 
			
		||||
        background: rgba(0, 0, 0, 0.16);
 | 
			
		||||
        border-radius: 28px;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      image {
 | 
			
		||||
        width: 100%;
 | 
			
		||||
        height: 320px;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ::v-deep .u-radio, ::v-deep .u-checkbox {
 | 
			
		||||
      align-items: baseline;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										52
									
								
								src/pages/askForm/askForm.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,52 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <section class="askForm">
 | 
			
		||||
    <template v-if="showDetail&&!isManager">
 | 
			
		||||
      <form-detail/>
 | 
			
		||||
    </template>
 | 
			
		||||
    <template v-else-if="isManager">
 | 
			
		||||
      <form-list ref="FormList"/>
 | 
			
		||||
    </template>
 | 
			
		||||
    <ai-loading v-else :tips="errMsg"/>
 | 
			
		||||
  </section>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import AiLoading from "../../components/AiLoading";
 | 
			
		||||
import {mapState} from "vuex";
 | 
			
		||||
import FormDetail from "./formDetail";
 | 
			
		||||
import FormList from "./formList";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: "askForm",
 | 
			
		||||
  components: {FormList, FormDetail, AiLoading},
 | 
			
		||||
  computed: {
 | 
			
		||||
    ...mapState(['openUser', 'user']),
 | 
			
		||||
    showDetail() {
 | 
			
		||||
      return !!this.$route.query?.id
 | 
			
		||||
    },
 | 
			
		||||
    isManager() {
 | 
			
		||||
      let {hash, query: {preview}} = this.$route
 | 
			
		||||
      if (preview) return false
 | 
			
		||||
      else if (hash == "#dev") return true
 | 
			
		||||
      else return hash != '#form' && !!this.user.id
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  data() {
 | 
			
		||||
    return {
 | 
			
		||||
      errMsg: "加载表单中..."
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  onReachBottom() {
 | 
			
		||||
    this.$refs?.FormList?.reachBottom()
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
.askForm {
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  height: 100%;
 | 
			
		||||
  background: #fff;
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										182
									
								
								src/pages/askForm/components/addList.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,182 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="form">
 | 
			
		||||
    <div class="form-list">
 | 
			
		||||
      <div
 | 
			
		||||
        class="form-list__item"
 | 
			
		||||
        @click="toAdd(`/pages/askForm/addForm?type=${index}`)"
 | 
			
		||||
        :style="{'background-image': `url(${$cdn}askform/${index + 1}.png)`}"
 | 
			
		||||
        v-for="(item, index) in itemList"
 | 
			
		||||
        :key="index">
 | 
			
		||||
        <h2>{{ item.name }}</h2>
 | 
			
		||||
        <div>立即创建</div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="template" v-if="list.length">
 | 
			
		||||
      <h2>共享模板</h2>
 | 
			
		||||
      <div class="template-list">
 | 
			
		||||
        <div class="template-item" v-for="(item, index) in list" :key="index" hover-class="bg-hover" @click="quote(item.id)">
 | 
			
		||||
          <image :src="`${$cdn}askform/6.png`" />
 | 
			
		||||
          <h2>{{ item.title }}</h2>
 | 
			
		||||
          <u-icon name="arrow-right" color="#E1E2E3" />
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
export default {
 | 
			
		||||
  name: 'addList',
 | 
			
		||||
  label: '新建项目',
 | 
			
		||||
 | 
			
		||||
  data () {
 | 
			
		||||
    return {
 | 
			
		||||
      itemList: [{
 | 
			
		||||
        name: '调查问卷'
 | 
			
		||||
      }, {
 | 
			
		||||
        name: '考试测评'
 | 
			
		||||
      }, {
 | 
			
		||||
        name: '报名登记'
 | 
			
		||||
      }, {
 | 
			
		||||
        name: '满意调查'
 | 
			
		||||
      }, {
 | 
			
		||||
        name: '投票评选'
 | 
			
		||||
      }],
 | 
			
		||||
      list: []
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  mounted () {
 | 
			
		||||
    this.getList()
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  methods: {
 | 
			
		||||
    toAdd (url) {
 | 
			
		||||
      uni.navigateTo({
 | 
			
		||||
        url
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    quote (id) {
 | 
			
		||||
      uni.navigateTo({
 | 
			
		||||
        url: `/pages/askForm/addForm?isQuote=1&id=${id}`
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    getList () {
 | 
			
		||||
      this.$http.post(`/app/appquestionnairetemplate/list`, null, {
 | 
			
		||||
        params: {
 | 
			
		||||
          current: 1,
 | 
			
		||||
          templateType: 1,
 | 
			
		||||
          size: 10000
 | 
			
		||||
        }
 | 
			
		||||
      }).then(res => {
 | 
			
		||||
        if (res.code == 0) {
 | 
			
		||||
          this.list = res.data.records
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
  .template {
 | 
			
		||||
    margin: 32px 32px 0;
 | 
			
		||||
    background: #fff;
 | 
			
		||||
    border-radius: 8px;
 | 
			
		||||
    overflow: hidden;
 | 
			
		||||
 | 
			
		||||
    & > h2 {
 | 
			
		||||
      height: 88px;
 | 
			
		||||
      line-height: 88px;
 | 
			
		||||
      padding: 0 24px;
 | 
			
		||||
      color: #333333;
 | 
			
		||||
      font-size: 30px;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .template-item {
 | 
			
		||||
      display: flex;
 | 
			
		||||
      align-items: center;
 | 
			
		||||
      height: 104px;
 | 
			
		||||
      padding: 0 24px;
 | 
			
		||||
      border-bottom: 1px solid #D8DDE6;
 | 
			
		||||
 | 
			
		||||
      &:active {
 | 
			
		||||
        background-color: #eee;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      &:last-child {
 | 
			
		||||
        border: none;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      image {
 | 
			
		||||
        width: 36px;
 | 
			
		||||
        height: 42px;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      i {
 | 
			
		||||
        font-size: 30px;
 | 
			
		||||
        color: #E1E2E3;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      h2 {
 | 
			
		||||
        flex: 1;
 | 
			
		||||
        padding: 0 18px;
 | 
			
		||||
        color: #333333;
 | 
			
		||||
        font-size: 28px;
 | 
			
		||||
        font-weight: normal;
 | 
			
		||||
        overflow: hidden;
 | 
			
		||||
        text-overflow:ellipsis;
 | 
			
		||||
        white-space: nowrap;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .form-list {
 | 
			
		||||
    display: flex;
 | 
			
		||||
    flex-wrap: wrap;
 | 
			
		||||
    padding: 0 32px 0;
 | 
			
		||||
 | 
			
		||||
    div {
 | 
			
		||||
      box-sizing: border-box;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .form-list__item {
 | 
			
		||||
      width: calc(50% - 13px);
 | 
			
		||||
      height: 216px;
 | 
			
		||||
      margin: 32px 24px 0 0;
 | 
			
		||||
      padding: 40px 20px 52px;
 | 
			
		||||
      background-color: #FFFFFF;
 | 
			
		||||
      border-radius: 8px;
 | 
			
		||||
      background-size: 100% 100%;
 | 
			
		||||
 | 
			
		||||
      &:active {
 | 
			
		||||
        background-color: #eee;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      &:nth-of-type(2n) {
 | 
			
		||||
        margin-right: 0;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      div {
 | 
			
		||||
        width: 148px;
 | 
			
		||||
        height: 48px;
 | 
			
		||||
        line-height: 48px;
 | 
			
		||||
        text-align: center;
 | 
			
		||||
        color: #fff;
 | 
			
		||||
        font-size: 28px;
 | 
			
		||||
        background: #6BA1F9;
 | 
			
		||||
        border-radius: 24px;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      h2 {
 | 
			
		||||
        margin-bottom: 32px;
 | 
			
		||||
        padding-left: 10px;
 | 
			
		||||
        color: #333333;
 | 
			
		||||
        font-weight: 700;
 | 
			
		||||
        font-size: 32px;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										497
									
								
								src/pages/askForm/components/list.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,497 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="form">
 | 
			
		||||
    <ai-top-fixed>
 | 
			
		||||
      <u-search placeholder="请输入标题" :show-action="false" search-icon-color="#ccc" v-model="search.title"
 | 
			
		||||
                @search="isMore = false, search.current = 1, getList()"/>
 | 
			
		||||
    </ai-top-fixed>
 | 
			
		||||
    <div class="form-list">
 | 
			
		||||
      <div class="form-item" v-for="(item, index) in list" :key="index"
 | 
			
		||||
           @click="info = item, id = item.id, isShow = true">
 | 
			
		||||
        <div class="form-item__top">
 | 
			
		||||
          <div class="form-item__left">
 | 
			
		||||
            <h2>{{ item.title }}</h2>
 | 
			
		||||
            <div class="form-item__left--info">
 | 
			
		||||
              <span>{{ item.createUserName }}</span>
 | 
			
		||||
              <span>{{ item.createUnitName }}</span>
 | 
			
		||||
              <span>{{ item.createTime.substr(0, item.createTime.length - 3) }}</span>
 | 
			
		||||
              <span>{{ $dict.getLabel('questionnaireType', item.type) }}</span>
 | 
			
		||||
            </div>
 | 
			
		||||
          </div>
 | 
			
		||||
          <div class="form-item__right">
 | 
			
		||||
            <h2>{{ item.dataCount }}</h2>
 | 
			
		||||
            <span>答卷数量</span>
 | 
			
		||||
          </div>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="form-item__bottom form-item__bottom--active">
 | 
			
		||||
          <i :style="{background: $dict.getColor('questionnaireStatus', item.status)}"></i>
 | 
			
		||||
          <span>{{ $dict.getLabel('questionnaireStatus', item.status) }}</span>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
      <ai-empty v-if="!list.length && isMore"></ai-empty>
 | 
			
		||||
    </div>
 | 
			
		||||
    <u-popup v-model="isShow" :closeable="false" mode="bottom" :z-index="11">
 | 
			
		||||
      <div class="popup">
 | 
			
		||||
        <h2>{{ info.title }}</h2>
 | 
			
		||||
        <div class="operate-list">
 | 
			
		||||
          <div class="operate-item" @click="toEdit">
 | 
			
		||||
            <div>
 | 
			
		||||
              <image :src="`${$cdn}askform/bj.png`"/>
 | 
			
		||||
            </div>
 | 
			
		||||
            <h3>编辑</h3>
 | 
			
		||||
          </div>
 | 
			
		||||
          <div class="operate-item" @click="linkTo('/pages/askForm/askForm?preview=1&id=' + id)">
 | 
			
		||||
            <div>
 | 
			
		||||
              <image :src="`${$cdn}askform/yl.png`"/>
 | 
			
		||||
            </div>
 | 
			
		||||
            <h3>预览</h3>
 | 
			
		||||
          </div>
 | 
			
		||||
          <div class="operate-item" @click="publish" v-if="info.status !== '1'">
 | 
			
		||||
            <div>
 | 
			
		||||
              <image :src="`${$cdn}askform/fb.png`"/>
 | 
			
		||||
            </div>
 | 
			
		||||
            <h3>发布</h3>
 | 
			
		||||
          </div>
 | 
			
		||||
          <div class="operate-item" @click="toStop" v-if="info.status === '1'">
 | 
			
		||||
            <div>
 | 
			
		||||
              <image :src="`${$cdn}askform/stop.png`"/>
 | 
			
		||||
            </div>
 | 
			
		||||
            <h3>停止</h3>
 | 
			
		||||
          </div>
 | 
			
		||||
          <div class="operate-item" @click="showShare">
 | 
			
		||||
            <div>
 | 
			
		||||
              <image :src="`${$cdn}askform/fx.png`"/>
 | 
			
		||||
            </div>
 | 
			
		||||
            <h3>分享</h3>
 | 
			
		||||
          </div>
 | 
			
		||||
          <div class="operate-item" @click="share(id)">
 | 
			
		||||
            <div>
 | 
			
		||||
              <image :src="`${$cdn}askform/mb.png`"/>
 | 
			
		||||
            </div>
 | 
			
		||||
            <h3>共享为模板</h3>
 | 
			
		||||
          </div>
 | 
			
		||||
          <div class="operate-item" @click="remove(id)">
 | 
			
		||||
            <div>
 | 
			
		||||
              <image :src="`${$cdn}askform/sc.png`"/>
 | 
			
		||||
            </div>
 | 
			
		||||
            <h3>删除</h3>
 | 
			
		||||
          </div>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="popup-btn" @click="isShow = false">关闭</div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </u-popup>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import AiTopFixed from '@/components/AiTopFixed'
 | 
			
		||||
import AiEmpty from '@/components/AiEmpty/AiEmpty'
 | 
			
		||||
import {mapActions} from 'vuex'
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: 'formList',
 | 
			
		||||
  label: '表单列表',
 | 
			
		||||
 | 
			
		||||
  data() {
 | 
			
		||||
    return {
 | 
			
		||||
      search: {
 | 
			
		||||
        current: 1,
 | 
			
		||||
        templateType: 0,
 | 
			
		||||
        title: ''
 | 
			
		||||
      },
 | 
			
		||||
      id: '',
 | 
			
		||||
      info: {},
 | 
			
		||||
      isMore: false,
 | 
			
		||||
      list: [],
 | 
			
		||||
      isShow: false
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  components: {
 | 
			
		||||
    AiEmpty,
 | 
			
		||||
    AiTopFixed
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  mounted() {
 | 
			
		||||
    this.injectJWeixin(['sendChatMessage', 'selectEnterpriseContact'])
 | 
			
		||||
    this.$dict.load(['questionnaireStatus', 'questionnaireType', 'questionnaireFieldType']).then(() => {
 | 
			
		||||
      this.getList()
 | 
			
		||||
    })
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  methods: {
 | 
			
		||||
    ...mapActions(['injectJWeixin', 'wxInvoke']),
 | 
			
		||||
 | 
			
		||||
    linkTo(url) {
 | 
			
		||||
      this.isShow = false
 | 
			
		||||
 | 
			
		||||
      uni.navigateTo({
 | 
			
		||||
        url
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    toStop() {
 | 
			
		||||
      this.$http.post(`/app/appquestionnairetemplate/stopRelease?id=${this.info.id}`).then(res => {
 | 
			
		||||
        if (res.code === 0) {
 | 
			
		||||
          this.$u.toast('停止成功')
 | 
			
		||||
          this.search.current = 1
 | 
			
		||||
          this.isShow = false
 | 
			
		||||
          this.isMore = false
 | 
			
		||||
          this.getList()
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    showShare() {
 | 
			
		||||
      if (this.info.status !== '1') {
 | 
			
		||||
        this.isShow = false
 | 
			
		||||
        return this.$u.toast(`该表单${this.info.status === '0' ? '未发布' : '已截止'},无法分享!`)
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      uni.showActionSheet({
 | 
			
		||||
        itemList: ['分享', '微信分享', '获取链接'],
 | 
			
		||||
        success: data => {
 | 
			
		||||
          this.$http.post(`/app/appquestionnairetemplate/queryQrCode?id=${this.info.id}`).then(res => {
 | 
			
		||||
            if (res.code == 0) {
 | 
			
		||||
              if (data.tapIndex === 2) {
 | 
			
		||||
                this.copy(res.data.linkUrl)
 | 
			
		||||
                this.isShow = false
 | 
			
		||||
              }
 | 
			
		||||
              if (data.tapIndex === 0 || data.tapIndex === 1) {
 | 
			
		||||
                this.injectJWeixin(['shareAppMessage', 'shareWechatMessage']).then(() => {
 | 
			
		||||
                  if (data.tapIndex === 0) {
 | 
			
		||||
                    this.wxInvoke(['shareAppMessage', {
 | 
			
		||||
                      title: this.info.title,
 | 
			
		||||
                      desc: this.info.tableExplain,
 | 
			
		||||
                      link: res.data.linkUrl,
 | 
			
		||||
                      imgUrl: this.info.headPicture
 | 
			
		||||
                    }, () => {
 | 
			
		||||
                      this.isShow = false
 | 
			
		||||
                    }])
 | 
			
		||||
                  } else {
 | 
			
		||||
                    this.wxInvoke(['shareWechatMessage', {
 | 
			
		||||
                      title: this.info.title,
 | 
			
		||||
                      desc: this.info.tableExplain,
 | 
			
		||||
                      link: res.data.linkUrl,
 | 
			
		||||
                      imgUrl: this.info.headPicture
 | 
			
		||||
                    }, () => {
 | 
			
		||||
                      this.isShow = false
 | 
			
		||||
                    }])
 | 
			
		||||
                  }
 | 
			
		||||
                })
 | 
			
		||||
              }
 | 
			
		||||
            }
 | 
			
		||||
          })
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    copy(link) {
 | 
			
		||||
      let oInput = document.createElement('input')
 | 
			
		||||
      oInput.value = link
 | 
			
		||||
      document.body.appendChild(oInput)
 | 
			
		||||
      oInput.select()
 | 
			
		||||
      document.execCommand('Copy')
 | 
			
		||||
      this.$u.toast('已复制')
 | 
			
		||||
      oInput.remove()
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    publish() {
 | 
			
		||||
      if (this.info.status === '1') {
 | 
			
		||||
        return this.$u.toast('该表单已发布')
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      this.linkTo(`/pages/askForm/formSetting?id=${this.info.id}&type=edit`)
 | 
			
		||||
      this.isShow = false
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    toEdit() {
 | 
			
		||||
      if (this.info.dataCount !== 0) {
 | 
			
		||||
        return this.$u.toast('该表单已有数据,无法编辑!')
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      uni.navigateTo({
 | 
			
		||||
        url: `/pages/askForm/addForm?id=${this.id}`
 | 
			
		||||
      })
 | 
			
		||||
 | 
			
		||||
      this.isShow = false
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    share(id) {
 | 
			
		||||
      this.$http.post(`/app/appquestionnairetemplate/share?id=${id}`).then(res => {
 | 
			
		||||
        if (res.code === 0) {
 | 
			
		||||
          this.$confirm('调查表单共享成功,其他成员可在新建项目时直接使用!', '', {
 | 
			
		||||
            showCancel: false
 | 
			
		||||
          })
 | 
			
		||||
          this.isShow = false
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    remove(id) {
 | 
			
		||||
      if (this.info.dataCount !== 0) {
 | 
			
		||||
        return this.$u.toast('该表单已有数据,无法删除!')
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      this.$confirm('确定删除该数据?').then(() => {
 | 
			
		||||
        this.$http.post(`/app/appquestionnairetemplate/delete?id=${id}`).then(res => {
 | 
			
		||||
          if (res.code == 0) {
 | 
			
		||||
            this.$u.toast('删除成功')
 | 
			
		||||
            this.isShow = false
 | 
			
		||||
            this.search.current = 1
 | 
			
		||||
            this.isMore = false
 | 
			
		||||
 | 
			
		||||
            this.getList()
 | 
			
		||||
          }
 | 
			
		||||
        })
 | 
			
		||||
      }).catch(() => {
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    reload() {
 | 
			
		||||
      this.isMore = false
 | 
			
		||||
      this.search.current = 1
 | 
			
		||||
 | 
			
		||||
      this.getList()
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    getList() {
 | 
			
		||||
      if (this.isMore) return
 | 
			
		||||
 | 
			
		||||
      this.$http.post(`/app/appquestionnairetemplate/list`, null, {
 | 
			
		||||
        params: {
 | 
			
		||||
          ...this.search,
 | 
			
		||||
          size: 10
 | 
			
		||||
        }
 | 
			
		||||
      }).then(res => {
 | 
			
		||||
        if (res.code == 0) {
 | 
			
		||||
          if (this.search.current > 1) {
 | 
			
		||||
            this.list = [...this.list, ...res.data.records]
 | 
			
		||||
          } else {
 | 
			
		||||
            this.list = res.data.records
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          uni.hideLoading()
 | 
			
		||||
 | 
			
		||||
          if (res.data.records.length < 10) {
 | 
			
		||||
            this.isMore = true
 | 
			
		||||
 | 
			
		||||
            return false
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          this.search.current = this.search.current + 1
 | 
			
		||||
        } else {
 | 
			
		||||
          uni.hideLoading()
 | 
			
		||||
        }
 | 
			
		||||
      }).catch(() => {
 | 
			
		||||
        uni.hideLoading()
 | 
			
		||||
      })
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
.form {
 | 
			
		||||
  ::v-deep .u-search {
 | 
			
		||||
    margin-bottom: 0 !important;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .popup {
 | 
			
		||||
    background: #F7F7F7;
 | 
			
		||||
 | 
			
		||||
    & > h2 {
 | 
			
		||||
      height: 72px;
 | 
			
		||||
      line-height: 72px;
 | 
			
		||||
      padding: 0 20px;
 | 
			
		||||
      color: #999999;
 | 
			
		||||
      font-size: 22px;
 | 
			
		||||
      text-align: center;
 | 
			
		||||
      border-bottom: 2px solid #D7D8DA;
 | 
			
		||||
      overflow: hidden;
 | 
			
		||||
      text-overflow: ellipsis;
 | 
			
		||||
      white-space: nowrap;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .popup-btn {
 | 
			
		||||
      height: 96px;
 | 
			
		||||
      line-height: 96px;
 | 
			
		||||
      text-align: center;
 | 
			
		||||
      color: #333333;
 | 
			
		||||
      font-size: 30px;
 | 
			
		||||
      background: #fff;
 | 
			
		||||
 | 
			
		||||
      &:active {
 | 
			
		||||
        background: #eee;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .operate-list {
 | 
			
		||||
      display: flex;
 | 
			
		||||
      flex-wrap: wrap;
 | 
			
		||||
      text-align: center;
 | 
			
		||||
      padding-bottom: 26px;
 | 
			
		||||
 | 
			
		||||
      .operate-item {
 | 
			
		||||
        width: 25%;
 | 
			
		||||
        font-size: 0;
 | 
			
		||||
        margin-top: 28px;
 | 
			
		||||
 | 
			
		||||
        &:active {
 | 
			
		||||
          opacity: 0.7;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        h3 {
 | 
			
		||||
          margin-top: 20px;
 | 
			
		||||
          color: #666666;
 | 
			
		||||
          font-size: 26px;
 | 
			
		||||
          font-weight: normal;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      image {
 | 
			
		||||
        width: 100px;
 | 
			
		||||
        height: 100px;
 | 
			
		||||
        border-radius: 16px;
 | 
			
		||||
        background: #fff;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  div {
 | 
			
		||||
    box-sizing: border-box;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .form-item {
 | 
			
		||||
    margin: 24px 25px 0;
 | 
			
		||||
    padding: 32px;
 | 
			
		||||
    background: #FFFFFF;
 | 
			
		||||
    border-radius: 16px;
 | 
			
		||||
 | 
			
		||||
    .form-item__bottom {
 | 
			
		||||
      display: flex;
 | 
			
		||||
      align-items: center;
 | 
			
		||||
      margin-top: 28px;
 | 
			
		||||
      color: #999999;
 | 
			
		||||
 | 
			
		||||
      i {
 | 
			
		||||
        width: 12px;
 | 
			
		||||
        height: 12px;
 | 
			
		||||
        margin-right: 6px;
 | 
			
		||||
        border-radius: 50%;
 | 
			
		||||
        background: #999999;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      span {
 | 
			
		||||
        font-size: 26px;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      &.form-item__bottom--active i {
 | 
			
		||||
        background: #3CB300;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .form-item__top {
 | 
			
		||||
      display: flex;
 | 
			
		||||
      justify-content: space-between;
 | 
			
		||||
      align-items: center;
 | 
			
		||||
 | 
			
		||||
      .form-item__right {
 | 
			
		||||
        text-align: center;
 | 
			
		||||
 | 
			
		||||
        h2 {
 | 
			
		||||
          line-height: 40px;
 | 
			
		||||
          margin-bottom: 16px;
 | 
			
		||||
          font-size: 32px;
 | 
			
		||||
          font-weight: 600;
 | 
			
		||||
          color: #1EA0FA;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        span {
 | 
			
		||||
          color: #999999;
 | 
			
		||||
          font-size: 22px;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .form-item__left {
 | 
			
		||||
        flex: 1;
 | 
			
		||||
        max-width: 80%;
 | 
			
		||||
        position: relative;
 | 
			
		||||
 | 
			
		||||
        &::after {
 | 
			
		||||
          position: absolute;
 | 
			
		||||
          right: -15px;
 | 
			
		||||
          top: 50%;
 | 
			
		||||
          width: 2px;
 | 
			
		||||
          height: 96px;
 | 
			
		||||
          background: #F5F5F5;
 | 
			
		||||
          content: '';
 | 
			
		||||
          transform: translateY(-50%);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        h2 {
 | 
			
		||||
          line-height: 44px;
 | 
			
		||||
          margin-bottom: 16px;
 | 
			
		||||
          color: #333;
 | 
			
		||||
          font-size: 32px;
 | 
			
		||||
          font-weight: 700;
 | 
			
		||||
          overflow: hidden;
 | 
			
		||||
          text-overflow: ellipsis;
 | 
			
		||||
          white-space: nowrap;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .form-item__left--info {
 | 
			
		||||
          display: flex;
 | 
			
		||||
          align-items: center;
 | 
			
		||||
          flex-wrap: wrap;
 | 
			
		||||
          color: #999;
 | 
			
		||||
          font-size: 20px;
 | 
			
		||||
 | 
			
		||||
          span {
 | 
			
		||||
            position: relative;
 | 
			
		||||
            margin-right: 24px;
 | 
			
		||||
 | 
			
		||||
            &::after {
 | 
			
		||||
              position: absolute;
 | 
			
		||||
              right: -12px;
 | 
			
		||||
              top: 50%;
 | 
			
		||||
              width: 2px;
 | 
			
		||||
              height: 20px;
 | 
			
		||||
              background: #D1D2D5;
 | 
			
		||||
              content: '';
 | 
			
		||||
              transform: translateY(-50%);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            &:last-child {
 | 
			
		||||
              margin-right: 0;
 | 
			
		||||
 | 
			
		||||
              &::after {
 | 
			
		||||
                display: none;
 | 
			
		||||
              }
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .type-0 {
 | 
			
		||||
    background: #2266FF !important;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .type-1 {
 | 
			
		||||
    background: rgba(34, 170, 153, 1) !important;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .type-2 {
 | 
			
		||||
    background: rgba(248, 180, 37, 1) !important;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .type-3 {
 | 
			
		||||
    background: rgba(102, 119, 187, 1) !important;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .type-4 {
 | 
			
		||||
    background: rgba(236, 68, 97, 1) !important;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										163
									
								
								src/pages/askForm/config.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,163 @@
 | 
			
		||||
export const components = [
 | 
			
		||||
	{
 | 
			
		||||
		type: 'radio',
 | 
			
		||||
		label: '单选',
 | 
			
		||||
		fixedLabel: '单选',
 | 
			
		||||
		value: '',
 | 
			
		||||
		points: '',
 | 
			
		||||
		icon: 'iconradio',
 | 
			
		||||
		isShowPoints: false,
 | 
			
		||||
		required: true,
 | 
			
		||||
		hasAnswer: false,
 | 
			
		||||
		answer: '',
 | 
			
		||||
		pointType: '0',
 | 
			
		||||
		pointDict: [
 | 
			
		||||
			{
 | 
			
		||||
				dictName: '此题有唯一答案和分值',
 | 
			
		||||
				dictValue: '0'
 | 
			
		||||
			},
 | 
			
		||||
			{
 | 
			
		||||
				dictName: '每个选项都有对应分值',
 | 
			
		||||
				dictValue: '1'
 | 
			
		||||
			}
 | 
			
		||||
		],
 | 
			
		||||
		options: [
 | 
			
		||||
			{
 | 
			
		||||
				label: '选项1',
 | 
			
		||||
				value: '',
 | 
			
		||||
				point: '',
 | 
			
		||||
				img: []
 | 
			
		||||
			},
 | 
			
		||||
			{
 | 
			
		||||
				label: '选项2',
 | 
			
		||||
				value: '',
 | 
			
		||||
				point: '',
 | 
			
		||||
				img: []
 | 
			
		||||
			}
 | 
			
		||||
		],
 | 
			
		||||
		title: ''
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		type: 'checkbox',
 | 
			
		||||
		label: '多选',
 | 
			
		||||
		fixedLabel: '多选',
 | 
			
		||||
		points: '',
 | 
			
		||||
		icon: 'iconcheck_box',
 | 
			
		||||
		isShowPoints: false,
 | 
			
		||||
		required: true,
 | 
			
		||||
		hasAnswer: false,
 | 
			
		||||
		answer: [],
 | 
			
		||||
		value: [],
 | 
			
		||||
		pointType: '0',
 | 
			
		||||
		pointDict: [
 | 
			
		||||
			{
 | 
			
		||||
				dictName: '此题有唯一答案和分值',
 | 
			
		||||
				dictValue: '0'
 | 
			
		||||
			},
 | 
			
		||||
			{
 | 
			
		||||
				dictName: '每个选项都有对应分值',
 | 
			
		||||
				dictValue: '1'
 | 
			
		||||
			},
 | 
			
		||||
			{
 | 
			
		||||
				dictName: '答对几项得几分,答错不得分',
 | 
			
		||||
				dictValue: '2'
 | 
			
		||||
			}
 | 
			
		||||
		],
 | 
			
		||||
		options: [
 | 
			
		||||
			{
 | 
			
		||||
				label: '选项1',
 | 
			
		||||
				value: '',
 | 
			
		||||
				point: '',
 | 
			
		||||
				img: [],
 | 
			
		||||
				checked: false
 | 
			
		||||
			},
 | 
			
		||||
			{
 | 
			
		||||
				label: '选项2',
 | 
			
		||||
				point: '',
 | 
			
		||||
				value: '',
 | 
			
		||||
				img: [],
 | 
			
		||||
				checked: false
 | 
			
		||||
			}
 | 
			
		||||
		],
 | 
			
		||||
		title: ''
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		type: 'select',
 | 
			
		||||
		label: '单下拉框',
 | 
			
		||||
		fixedLabel: '单下拉框',
 | 
			
		||||
		value: '',
 | 
			
		||||
		points: '',
 | 
			
		||||
		icon: 'iconSelect',
 | 
			
		||||
		isShowPoints: false,
 | 
			
		||||
		required: true,
 | 
			
		||||
		hasAnswer: false,
 | 
			
		||||
		answer: '',
 | 
			
		||||
		pointType: '0',
 | 
			
		||||
		placeholder: '请选择',
 | 
			
		||||
		pointDict: [
 | 
			
		||||
			{
 | 
			
		||||
				dictName: '此题有唯一答案和分值',
 | 
			
		||||
				dictValue: '0'
 | 
			
		||||
			},
 | 
			
		||||
			{
 | 
			
		||||
				dictName: '每个选项都有对应分值',
 | 
			
		||||
				dictValue: '1'
 | 
			
		||||
			}
 | 
			
		||||
		],
 | 
			
		||||
		options: [
 | 
			
		||||
			{
 | 
			
		||||
				label: '选项1',
 | 
			
		||||
				value: '',
 | 
			
		||||
				point: '',
 | 
			
		||||
				img: []
 | 
			
		||||
			},
 | 
			
		||||
			{
 | 
			
		||||
				label: '选项2',
 | 
			
		||||
				value: '',
 | 
			
		||||
				point: '',
 | 
			
		||||
				img: []
 | 
			
		||||
			}
 | 
			
		||||
		],
 | 
			
		||||
		title: ''
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		type: 'input',
 | 
			
		||||
		label: '单行填空',
 | 
			
		||||
		fixedLabel: '单行填空',
 | 
			
		||||
		value: '',
 | 
			
		||||
		pointType: '0',
 | 
			
		||||
		icon: 'icontext_box',
 | 
			
		||||
		isShowPoints: false,
 | 
			
		||||
		points: '',
 | 
			
		||||
		required: true,
 | 
			
		||||
		hasAnswer: false,
 | 
			
		||||
		placeholder: '请输入...',
 | 
			
		||||
		answer: ''
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		type: 'textarea',
 | 
			
		||||
		label: '多行填空',
 | 
			
		||||
		fixedLabel: '多行填空',
 | 
			
		||||
		pointType: '0',
 | 
			
		||||
		icon: 'icontext_area',
 | 
			
		||||
		points: '',
 | 
			
		||||
		isShowPoints: false,
 | 
			
		||||
		required: true,
 | 
			
		||||
		hasAnswer: false,
 | 
			
		||||
		answer: '',
 | 
			
		||||
		placeholder: '请输入...',
 | 
			
		||||
		value: ''
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		type: 'upload',
 | 
			
		||||
		label: '上传图片',
 | 
			
		||||
		fixedLabel: '上传图片',
 | 
			
		||||
		value: '',
 | 
			
		||||
		icon: 'iconpic',
 | 
			
		||||
		isShowPoints: false,
 | 
			
		||||
		points: '',
 | 
			
		||||
		required: true,
 | 
			
		||||
		hasAnswer: false,
 | 
			
		||||
		answer: ''
 | 
			
		||||
	}
 | 
			
		||||
];
 | 
			
		||||
							
								
								
									
										535
									
								
								src/pages/askForm/filedConfig.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,535 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="form-config">
 | 
			
		||||
    <div class="config-group">
 | 
			
		||||
      <div class="config-item">
 | 
			
		||||
        <u-input class="form-maintitle" :maxlength="200" v-model="config.label" :placeholder="`请输入${config.fixedLabel}标题 ${config.required ? '(必填)' : ''}`"  placeholder-style="color: #999999; font-weight: 600" />
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="config-item__select--wrapper" v-if="['radio', 'select', 'checkbox'].includes(config.type)">
 | 
			
		||||
        <div class="config-item__select" v-for="(item, index) in config.options" :key="index">
 | 
			
		||||
          <image class="config-icon" :src="`${$cdn}askform/del.png`" @click="removeOptions(index)" />
 | 
			
		||||
          <div class="config-item__upload" v-if="config.type !== 'select'" @click="upload(index)">
 | 
			
		||||
            <u-icon color="#8c9dc3" name="plus" v-if="!item.img.length"></u-icon>
 | 
			
		||||
            <image v-else :src="item.img[0].url" />
 | 
			
		||||
          </div>
 | 
			
		||||
          <div class="textarea">
 | 
			
		||||
           <textarea type="textarea" placeholder-style="color: #CDCDCF" :auto-height="true" v-model="item.label" :maxlength="100" placeholder="请输入选项" />
 | 
			
		||||
          </div>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="config-item__select config-item__select--add" @click="addOptions">
 | 
			
		||||
          <image class="config-icon" :src="`${$cdn}askform/zj.png`" />
 | 
			
		||||
          <span>添加选项</span>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="config-group">
 | 
			
		||||
      <div class="config-item" v-if="!['radio', 'upload', 'checkbox', 'select'].includes(config.type)">
 | 
			
		||||
        <div class="config-item__left">
 | 
			
		||||
          <span>说明文字</span>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="config-item__right">
 | 
			
		||||
          <u-input v-model="config.placeholder" placeholder="请输入说明文字" input-align="right" />
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="config-item">
 | 
			
		||||
        <div class="config-item__left">
 | 
			
		||||
          <span>是否必填</span>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="config-item__right">
 | 
			
		||||
          <u-switch v-model="config.required" active-value="1" inactive-value="0" :size="40" active-color="#1088F9"></u-switch>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="config-item" v-if="!['upload'].includes(config.type)">
 | 
			
		||||
        <div class="config-item__left">
 | 
			
		||||
          <span>答案与分值</span>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="config-item__right">
 | 
			
		||||
          <u-switch v-model="config.isShowPoints" :size="40" active-color="#1088F9"></u-switch>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="config-item" v-if="['input', 'textarea'].includes(config.type) && config.isShowPoints">
 | 
			
		||||
        <div class="config-item__left">
 | 
			
		||||
          <span>正确答案</span>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="config-item__right">
 | 
			
		||||
          <u-input v-model="config.answer" placeholder="请输入正确答案" input-align="right" />
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="config-item" v-if="['radio', 'select'].includes(config.type) && config.isShowPoints && config.pointType === '0'">
 | 
			
		||||
        <div class="config-item__left">
 | 
			
		||||
          <span>正确答案</span>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="config-item__right config-item__text" @click="isShowAnswer = true">
 | 
			
		||||
          <span>{{ config.answer ? config.answer : '请选择正确答案' }}</span>
 | 
			
		||||
          <u-icon name="arrow-down-fill" color="#c0c4cc" size="24"></u-icon>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="config-item config-item__checkbox" v-if="config.isShowPoints && ['radio', 'select', 'checkbox'].includes(config.type)">
 | 
			
		||||
        <div class="config-item__left">
 | 
			
		||||
          <span>计分方式</span>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="config-item__right" @click="isShowType = true">
 | 
			
		||||
          <span>{{ pointTypeName ? pointTypeName : '请选择' }}</span>
 | 
			
		||||
          <u-icon name="arrow-right" color="#E1E2E3" />
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="config-item config-item__answer config-item__checkbox" v-if="['checkbox'].includes(config.type) && config.isShowPoints && config.pointType === '0'">
 | 
			
		||||
        <div class="config-item__left">
 | 
			
		||||
          <span>正确答案</span>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="config-item__right">
 | 
			
		||||
          <u-checkbox-group wrap @change="onCheckboxChange">
 | 
			
		||||
            <u-checkbox v-model="field.checked" :name="field.label"  v-if="field.label" v-for="(field, i) in config.options" :key="i">
 | 
			
		||||
              <span>{{ field.label }}</span>
 | 
			
		||||
            </u-checkbox>
 | 
			
		||||
          </u-checkbox-group>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="config-item" v-if="config.isShowPoints && config.pointType === '0'">
 | 
			
		||||
        <div class="config-item__left">
 | 
			
		||||
          <span>本题分值</span>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="config-item__right">
 | 
			
		||||
          <u-input v-model="config.points" type="number" placeholder="请输入本题分值" input-align="right" />
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div v-if="config.isShowPoints && config.pointType === '1'">
 | 
			
		||||
        <div class="config-item" v-for="(item, index) in config.options" :key="index">
 | 
			
		||||
          <div class="config-item__left">
 | 
			
		||||
            <span>{{ item.label }}</span>
 | 
			
		||||
          </div>
 | 
			
		||||
          <div class="config-item__right">
 | 
			
		||||
            <u-input v-model="item.point" placeholder="请输入分值" input-align="right" />
 | 
			
		||||
          </div>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="config-item config-item__point" v-if="config.isShowPoints && config.pointType === '2'">
 | 
			
		||||
        <u-checkbox-group wrap @change="onCheckboxChange">
 | 
			
		||||
          <u-checkbox v-model="field.checked" :name="field.label" v-if="field.label" v-for="(field, i) in config.options" :key="i">
 | 
			
		||||
            <span>{{ field.label }}</span>
 | 
			
		||||
            <u-input v-model="field.point" type="number" placeholder="请输入分值" input-align="right" />
 | 
			
		||||
          </u-checkbox>
 | 
			
		||||
        </u-checkbox-group>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="config-item" v-if="config.isShowPoints && config.pointType === '2'">
 | 
			
		||||
        <div class="config-item__left" style="padding-left: 20px">
 | 
			
		||||
          <span>全部答对</span>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="config-item__right">
 | 
			
		||||
          <u-input v-model="config.points" type="number" placeholder="请输入全部答对分值" input-align="right" />
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <u-select :list="config.options" :default-value="defaultAnswer" value-name="value" label-name="label" v-model="isShowAnswer" @confirm="answerChange"></u-select>
 | 
			
		||||
    <u-select :list="config.pointDict" :default-value="defaultType" value-name="dictValue" label-name="dictName" v-model="isShowType" @confirm="pointTypeChange"></u-select>
 | 
			
		||||
    <div class="add-form__footer">
 | 
			
		||||
      <div @click="back">
 | 
			
		||||
        <span>取消</span>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div @click="confirm">确定</div>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import { components } from './config'
 | 
			
		||||
export default {
 | 
			
		||||
  data () {
 | 
			
		||||
    return {
 | 
			
		||||
      index: '',
 | 
			
		||||
      isShowType: false,
 | 
			
		||||
      isShowAnswer: false,
 | 
			
		||||
      config: {
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  onLoad (query) {
 | 
			
		||||
    if (query.type) {
 | 
			
		||||
      this.config = JSON.parse(JSON.stringify(components.filter(v => v.type === query.type)[0]))
 | 
			
		||||
    } else {
 | 
			
		||||
      this.config = JSON.parse(query.config)
 | 
			
		||||
      this.index = query.index
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  computed: {
 | 
			
		||||
    pointTypeName () {
 | 
			
		||||
      if (!this.config.pointDict) return ''
 | 
			
		||||
 | 
			
		||||
      return this.config.pointDict.filter(v => v.dictValue === this.config.pointType)[0].dictName
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    defaultType () {
 | 
			
		||||
      if (!this.config.pointType) return [0]
 | 
			
		||||
 | 
			
		||||
      return [Number(this.config.pointType)]
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    defaultAnswer () {
 | 
			
		||||
      if (!this.config.answer) return [0]
 | 
			
		||||
 | 
			
		||||
      let index = 0
 | 
			
		||||
      if (this.config.answer) {
 | 
			
		||||
        this.config.options.forEach((v, i) => {
 | 
			
		||||
          if (v.label === this.config.answer) {
 | 
			
		||||
            index = i
 | 
			
		||||
          }
 | 
			
		||||
        })
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      return [index]
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  methods: {
 | 
			
		||||
    answerChange (e) {
 | 
			
		||||
      this.config.answer = e[0].label
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    pointTypeChange (e) {
 | 
			
		||||
      console.log(e)
 | 
			
		||||
      this.config.pointType = e[0].value
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    onCheckboxChange (e) {
 | 
			
		||||
      this.config.answer = e
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    upload (index) {
 | 
			
		||||
      let params = {
 | 
			
		||||
        count: 1,
 | 
			
		||||
        sizeType: ['compressed'],
 | 
			
		||||
        sourceType: ['album', 'camera'],
 | 
			
		||||
        success: (res) => {
 | 
			
		||||
          let count = this.fileList?.length + (res.tempFiles?.length || res.tempFile ? 1 : 0)
 | 
			
		||||
          if (count > 1) {
 | 
			
		||||
            return this.$u.toast(`不能超过1个`)
 | 
			
		||||
          }
 | 
			
		||||
          if (res.tempFiles) {
 | 
			
		||||
            res.tempFiles.map((item) => {
 | 
			
		||||
              this.uploadFile(item, index)
 | 
			
		||||
            })
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      uni.chooseImage(params)
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    uploadFile (img, index) {
 | 
			
		||||
      uni.showLoading({title: '上传中'})
 | 
			
		||||
      let formData = new FormData()
 | 
			
		||||
      formData.append('file', img)
 | 
			
		||||
      this.$http.post('/admin/file/add2', formData).then((res) => {
 | 
			
		||||
        uni.hideLoading()
 | 
			
		||||
        if (res?.data) {
 | 
			
		||||
          this.$u.toast('上传成功!')
 | 
			
		||||
          this.$set(this.config.options[index], 'img', [res.data])
 | 
			
		||||
        }
 | 
			
		||||
      }).catch(res => {
 | 
			
		||||
        this.$u.toast(res)
 | 
			
		||||
        uni.hideLoading()
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    removeOptions (index) {
 | 
			
		||||
      const len = this.config.options.length
 | 
			
		||||
      const label = this.config.options[index].label
 | 
			
		||||
      if (len === 2) {
 | 
			
		||||
        return this.$u.toast('选项不能少于2个')
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (this.config.type === 'checkbox') {
 | 
			
		||||
        const answerIndex = this.config.answer.indexOf(label)
 | 
			
		||||
        if (answerIndex > -1) {
 | 
			
		||||
          this.config.answer.splice(answerIndex, 1)
 | 
			
		||||
        }
 | 
			
		||||
      } else {
 | 
			
		||||
        if (label === this.config.answer) {
 | 
			
		||||
          this.config.answer = ''
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      this.config.options.splice(index, 1)
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    back () {
 | 
			
		||||
      uni.navigateBack({
 | 
			
		||||
        delta: 1
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    confirm () {
 | 
			
		||||
      uni.$emit('filedConfig', {
 | 
			
		||||
        config: this.config,
 | 
			
		||||
        index: this.index === '' ? '-1' : this.index
 | 
			
		||||
      })
 | 
			
		||||
      uni.navigateBack({
 | 
			
		||||
        delta: 1
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    addOptions () {
 | 
			
		||||
      const len = this.config.options.length
 | 
			
		||||
      let label = `选项${len + 1}`
 | 
			
		||||
 | 
			
		||||
      const index= this.config.options.findIndex(v => label === v.label)
 | 
			
		||||
      if (index > -1) {
 | 
			
		||||
        label = `新选项${len + 1}`
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      this.config.options.push({
 | 
			
		||||
        label: label,
 | 
			
		||||
        value: '',
 | 
			
		||||
        point: '',
 | 
			
		||||
        img: '',
 | 
			
		||||
        checked: false
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
  .form-config {
 | 
			
		||||
    box-sizing: border-box;
 | 
			
		||||
    padding-bottom: 130px;
 | 
			
		||||
 | 
			
		||||
    .form-maintitle {
 | 
			
		||||
      ::v-deep .uni-input-input {
 | 
			
		||||
        font-size: 36px;
 | 
			
		||||
        font-weight: 600;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .config-item__select--wrapper {
 | 
			
		||||
      .config-item__select {
 | 
			
		||||
        display: flex;
 | 
			
		||||
        align-items: center;
 | 
			
		||||
 | 
			
		||||
        ::v-deep .u-input__input {
 | 
			
		||||
          height: 100%;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .textarea {
 | 
			
		||||
          flex: 1;
 | 
			
		||||
          display: flex;
 | 
			
		||||
          align-items: center;
 | 
			
		||||
          min-height: 104px;
 | 
			
		||||
          padding: 16px 0;
 | 
			
		||||
          font-size: 28px;
 | 
			
		||||
          border-bottom: 1px solid #dfe8f8;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        textarea {
 | 
			
		||||
          width: 100%;
 | 
			
		||||
          font-size: 28px;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .config-icon {
 | 
			
		||||
          width: 36px;
 | 
			
		||||
          height: 36px;
 | 
			
		||||
          margin-right: 12px;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .config-item__select--add {
 | 
			
		||||
        height: 120px;
 | 
			
		||||
 | 
			
		||||
        .config-icon {
 | 
			
		||||
          margin-right: 18px;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        span {
 | 
			
		||||
          color: #1D74F4;
 | 
			
		||||
          font-size: 30px;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .config-group {
 | 
			
		||||
      margin-bottom: 32px;
 | 
			
		||||
      padding: 0 32px;
 | 
			
		||||
      background: #fff;
 | 
			
		||||
 | 
			
		||||
      .config-item__upload {
 | 
			
		||||
        display: flex;
 | 
			
		||||
        align-items: center;
 | 
			
		||||
        justify-content: center;
 | 
			
		||||
        width: 60px;
 | 
			
		||||
        height: 60px;
 | 
			
		||||
        margin-right: 20px;
 | 
			
		||||
        border: 1px solid rgb(208, 212, 220);
 | 
			
		||||
        background-color: #fbfdff;
 | 
			
		||||
 | 
			
		||||
        image {
 | 
			
		||||
          width: 100%;
 | 
			
		||||
          height: 100%;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .config-item {
 | 
			
		||||
        display: flex;
 | 
			
		||||
        align-items: center;
 | 
			
		||||
        justify-content: space-between;
 | 
			
		||||
        min-height: 100px;
 | 
			
		||||
        padding: 16px 0;
 | 
			
		||||
        border-bottom: 1px solid #dfe8f8;
 | 
			
		||||
 | 
			
		||||
        &:last-child {
 | 
			
		||||
          border: none;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        ::v-deep .u-radio__label, ::v-deep .u-checkbox__label {
 | 
			
		||||
          margin-right: 0;
 | 
			
		||||
          font-size: 28px;
 | 
			
		||||
 | 
			
		||||
          span {
 | 
			
		||||
            max-width: 400rpx;
 | 
			
		||||
            line-height: 1.2;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .config-item__left {
 | 
			
		||||
          max-width: 400px;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .config-item__right {
 | 
			
		||||
          flex: 1;
 | 
			
		||||
          text-align: right;
 | 
			
		||||
          padding-left: 30px;
 | 
			
		||||
 | 
			
		||||
          &.config-item__text {
 | 
			
		||||
            display: flex;
 | 
			
		||||
            align-items: center;
 | 
			
		||||
            justify-content: flex-end;
 | 
			
		||||
 | 
			
		||||
            span {
 | 
			
		||||
              max-width: 400px;
 | 
			
		||||
              margin-right: 10px;
 | 
			
		||||
              overflow: hidden;
 | 
			
		||||
              text-overflow: ellipsis;
 | 
			
		||||
              white-space: nowrap;
 | 
			
		||||
              word-break: keep-all;
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          .text {
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        &.config-item__answer {
 | 
			
		||||
          display: block;
 | 
			
		||||
          padding: 20px 0;
 | 
			
		||||
 | 
			
		||||
          .config-item__left {
 | 
			
		||||
            margin-bottom: 32rpx;
 | 
			
		||||
            span {
 | 
			
		||||
              word-break: break-all;
 | 
			
		||||
              color: #333;
 | 
			
		||||
              font-size: 30px;
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          .config-item__right {
 | 
			
		||||
            width: 100%;
 | 
			
		||||
            padding-left: 0;
 | 
			
		||||
            text-align: left;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      ::v-deep .u-checkbox {
 | 
			
		||||
        align-items: baseline;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .config-item__checkbox {
 | 
			
		||||
        height: auto;
 | 
			
		||||
        padding: 14px 0;
 | 
			
		||||
 | 
			
		||||
        ::v-deep .u-checkbox, ::v-deep .u-radio {
 | 
			
		||||
          // justify-content: flex-end;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      .config-item__point {
 | 
			
		||||
        height: auto;
 | 
			
		||||
        padding: 0;
 | 
			
		||||
 | 
			
		||||
        ::v-deep .u-checkbox {
 | 
			
		||||
          justify-content: inherit;
 | 
			
		||||
          min-height: 100px;
 | 
			
		||||
          padding: 14px 0;
 | 
			
		||||
          border-bottom: 1px solid #eee;
 | 
			
		||||
 | 
			
		||||
          &:last-child {
 | 
			
		||||
            border: none;
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          .u-checkbox__label {
 | 
			
		||||
            display: flex;
 | 
			
		||||
            align-items: center;
 | 
			
		||||
            justify-content: space-between;
 | 
			
		||||
            flex: 1;
 | 
			
		||||
            margin-right: 0;
 | 
			
		||||
 | 
			
		||||
            .u-input {
 | 
			
		||||
              flex: 1;
 | 
			
		||||
              max-width: 400px;
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    * {
 | 
			
		||||
      box-sizing: border-box;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .add-form__footer {
 | 
			
		||||
      display: flex;
 | 
			
		||||
      align-items: center;
 | 
			
		||||
      position: fixed;
 | 
			
		||||
      left: 0;
 | 
			
		||||
      bottom: 0;
 | 
			
		||||
      z-index: 1;
 | 
			
		||||
      width: 100%;
 | 
			
		||||
      height: 112px;
 | 
			
		||||
      text-align: center;
 | 
			
		||||
 | 
			
		||||
      div {
 | 
			
		||||
        display: flex;
 | 
			
		||||
        align-items: center;
 | 
			
		||||
        justify-content: center;
 | 
			
		||||
        flex: 1;
 | 
			
		||||
        height: 100%;
 | 
			
		||||
        text-align: center;
 | 
			
		||||
        background: #fff;
 | 
			
		||||
 | 
			
		||||
        &:first-child:active {
 | 
			
		||||
          background: #eee;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        &:last-child {
 | 
			
		||||
          color: #fff;
 | 
			
		||||
          font-size: 36px;
 | 
			
		||||
          background: #3192F4;
 | 
			
		||||
 | 
			
		||||
          &:active {
 | 
			
		||||
            opacity: 0.8;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        span {
 | 
			
		||||
          flex: 1;
 | 
			
		||||
          height: 100%;
 | 
			
		||||
          line-height: 112px;
 | 
			
		||||
          color: #333333;
 | 
			
		||||
          font-size: 32px;
 | 
			
		||||
 | 
			
		||||
          &:active {
 | 
			
		||||
            background: #eee;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										405
									
								
								src/pages/askForm/formDetail.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,405 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <section class="formDetail">
 | 
			
		||||
    <ai-result v-if="result.tips" v-bind="result">
 | 
			
		||||
      <template v-if="isExam" #extra>
 | 
			
		||||
        <div flex class="scorePane">
 | 
			
		||||
          <div>成绩</div>
 | 
			
		||||
          <div class="fill"><em v-html="score"/> 分</div>
 | 
			
		||||
        </div>
 | 
			
		||||
      </template>
 | 
			
		||||
    </ai-result>
 | 
			
		||||
    <template v-else-if="form.id">
 | 
			
		||||
      <image v-if="form.headPicture" class="headPicture" :src="form.headPicture"/>
 | 
			
		||||
      <b class="title">{{ form.title || "标题" }}</b>
 | 
			
		||||
      <div class="tableExplain">{{ form.tableExplain }}</div>
 | 
			
		||||
      <u-form class="content" label-position="top">
 | 
			
		||||
        <u-form-item class="item" v-for="(op,i) in fields" :key="i" :label="(i+1)+'.'+op.fieldName"
 | 
			
		||||
                     :required="op.fieldInfo.required==1">
 | 
			
		||||
          <template v-if="op.fieldType=='input'">
 | 
			
		||||
            <input v-model="op.fieldValue" :placeholder="op.fieldInfo.placeholder" :disabled="isResult"/>
 | 
			
		||||
          </template>
 | 
			
		||||
          <template v-else-if="op.fieldType=='textarea'">
 | 
			
		||||
            <textarea v-model="op.fieldValue" :disabled="isResult" :placeholder="op.fieldInfo.placeholder"/>
 | 
			
		||||
          </template>
 | 
			
		||||
          <template v-else-if="op.fieldType=='upload'">
 | 
			
		||||
            <ai-uploader @list="v=>op.fieldValue=v.map(e=>e.url)" :def="op.fieldValue" :disabled="isResult"
 | 
			
		||||
                         preview/>
 | 
			
		||||
          </template>
 | 
			
		||||
          <u-row v-else-if="op.fieldType=='radio'">
 | 
			
		||||
            <radio-group @change="({detail})=>op.fieldValue=detail.value">
 | 
			
		||||
              <div class="option" flex v-for="option in op.fieldInfo.options" :key="option.label">
 | 
			
		||||
                <radio :value="option.label" :disabled="isResult" :checked="op.fieldValue==option.label"/>
 | 
			
		||||
                <ai-image v-if="option.img" :src="option.img" preview/>
 | 
			
		||||
                <div class="label fill">{{ option.label }}</div>
 | 
			
		||||
              </div>
 | 
			
		||||
            </radio-group>
 | 
			
		||||
          </u-row>
 | 
			
		||||
          <u-row v-else-if="op.fieldType=='checkbox'">
 | 
			
		||||
            <checkbox-group @change="({detail})=>op.fieldValue=detail.value">
 | 
			
		||||
              <div class="option" flex v-for="option in op.fieldInfo.options" :key="option.label">
 | 
			
		||||
                <checkbox :value="option.label" :disabled="isResult"
 | 
			
		||||
                          :checked="option.checked"/>
 | 
			
		||||
                <ai-image v-if="option.img" :src="option.img" preview/>
 | 
			
		||||
                <div class="label fill">{{ option.label }}</div>
 | 
			
		||||
              </div>
 | 
			
		||||
            </checkbox-group>
 | 
			
		||||
          </u-row>
 | 
			
		||||
          <template v-else-if="op.fieldType=='select'">
 | 
			
		||||
            <ai-select @data="v=>op.fieldValue=v.map(e=>e.value)" :list="op.fieldInfo.options" :disabled="isResult">
 | 
			
		||||
              <div class="option" flex>
 | 
			
		||||
                <div class="label fill" v-if="op.fieldValue">{{ op.fieldValue.toString() }}</div>
 | 
			
		||||
                <i class="fill" v-else>请选择</i>
 | 
			
		||||
                <u-icon name="arrow-right" color="#ddd"/>
 | 
			
		||||
              </div>
 | 
			
		||||
            </ai-select>
 | 
			
		||||
          </template>
 | 
			
		||||
        </u-form-item>
 | 
			
		||||
      </u-form>
 | 
			
		||||
      <div class="bottom" v-if="!(isPreview||isResult)">
 | 
			
		||||
        <div class="bottomBtn" @tap="handleSubmit">提交</div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </template>
 | 
			
		||||
    <ai-loading v-else tips="调查问卷加载中..."/>
 | 
			
		||||
  </section>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
 | 
			
		||||
import UForm from "../../uview/components/u-form/u-form";
 | 
			
		||||
import UFormItem from "../../uview/components/u-form-item/u-form-item";
 | 
			
		||||
import {mapActions, mapState} from "vuex";
 | 
			
		||||
import UInput from "../../uview/components/u-input/u-input";
 | 
			
		||||
import AiTextarea from "../../components/AiTextarea";
 | 
			
		||||
import AiUploader from "../../components/AiUploader";
 | 
			
		||||
import AiSelect from "../../components/AiSelect";
 | 
			
		||||
import URadio from "../../uview/components/u-radio/u-radio";
 | 
			
		||||
import AiLoading from "../../components/AiLoading";
 | 
			
		||||
import AiResult from "../../components/AiResult";
 | 
			
		||||
import AiImage from "../../components/AiImage";
 | 
			
		||||
import AiBack from "../../components/AiBack";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: "formDetail",
 | 
			
		||||
  components: {
 | 
			
		||||
    AiBack,
 | 
			
		||||
    AiImage,
 | 
			
		||||
    AiResult,
 | 
			
		||||
    AiLoading,
 | 
			
		||||
    URadio,
 | 
			
		||||
    AiSelect,
 | 
			
		||||
    AiUploader,
 | 
			
		||||
    AiTextarea,
 | 
			
		||||
    UInput,
 | 
			
		||||
    UFormItem,
 | 
			
		||||
    UForm
 | 
			
		||||
  },
 | 
			
		||||
  computed: {
 | 
			
		||||
    ...mapState(['openUser', 'token']),
 | 
			
		||||
    isExam() {
 | 
			
		||||
      return this.form?.type == 1
 | 
			
		||||
    },
 | 
			
		||||
    isPreview() {
 | 
			
		||||
      return !!this.$route.query?.preview
 | 
			
		||||
    },
 | 
			
		||||
    isResult() {
 | 
			
		||||
      return !!this.$route.query?.result
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  data() {
 | 
			
		||||
    return {
 | 
			
		||||
      form: {},
 | 
			
		||||
      fields: [],
 | 
			
		||||
      checkUser: false,
 | 
			
		||||
      result: {},
 | 
			
		||||
      score: 0
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  watch: {
 | 
			
		||||
    form: {
 | 
			
		||||
      deep: true,
 | 
			
		||||
      handler(v) {
 | 
			
		||||
        this.fields = v?.fields?.map(e => {
 | 
			
		||||
          let fieldInfo = JSON.parse(e.fieldInfo)
 | 
			
		||||
          fieldInfo?.options?.map(op => {
 | 
			
		||||
            op.img = op?.img?.[0]?.url
 | 
			
		||||
            op.checked = !!e.fieldValue?.split(",")?.includes(op.label)
 | 
			
		||||
          })
 | 
			
		||||
          if (e.fieldType == 'select') {
 | 
			
		||||
            fieldInfo.options = fieldInfo.options.map(e => ({...e, value: e.label, label: e.label}))
 | 
			
		||||
          }
 | 
			
		||||
          return {...e, fieldInfo}
 | 
			
		||||
        }) || []
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    ...mapActions(['getUserInfo']),
 | 
			
		||||
    getForm() {
 | 
			
		||||
      let {id} = this.$route.query
 | 
			
		||||
      this.$http.post("/app/appquestionnairetemplate/queryDetailById", null, {
 | 
			
		||||
        params: {id}
 | 
			
		||||
      }).then(res => {
 | 
			
		||||
        if (res?.data) {
 | 
			
		||||
          this.form = res.data
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
    validateForm() {
 | 
			
		||||
      return !this.fields.some(e => {
 | 
			
		||||
        if (!!e?.fieldInfo?.required && !e.fieldValue?.toString()) {
 | 
			
		||||
          this.$u.toast(e.fieldName + "不能为空!")
 | 
			
		||||
          return true
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
    handleSubmit() {
 | 
			
		||||
      if (this.validateForm()) {
 | 
			
		||||
        this.handleScore()
 | 
			
		||||
        let {avatar: avatarUrl, openId, name: nickName, type: userType, unionId, corpName} = this.openUser
 | 
			
		||||
        this.$http.post("/app/appquestionnairetemplate/commit", {
 | 
			
		||||
          fields: this.fields.map(e => ({
 | 
			
		||||
            ...e,
 | 
			
		||||
            fieldInfo: JSON.stringify(e.fieldInfo),
 | 
			
		||||
            fieldValue: e.fieldValue?.toString()
 | 
			
		||||
          })),
 | 
			
		||||
          avatarUrl, openId, nickName, userType, unionId, corpName,
 | 
			
		||||
          totalScore: this.score,
 | 
			
		||||
          questionnaireTemplateId: this.$route.query.id
 | 
			
		||||
        }).then(res => {
 | 
			
		||||
          if (res?.code == 0) {
 | 
			
		||||
            this.result = {
 | 
			
		||||
              tips: "提交成功!感谢参与",
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        })
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    handleScore() {
 | 
			
		||||
      this.score = 0
 | 
			
		||||
      this.isExam && this.fields.map(field => {
 | 
			
		||||
        let item = field?.fieldInfo || {}
 | 
			
		||||
        let current = 0
 | 
			
		||||
        const calcScore = point => (current += (Number(point) || 0))
 | 
			
		||||
        if (item?.pointType == 0) {//此题有唯一答案和分值
 | 
			
		||||
          field.fieldValue?.toString() == item.answer?.toString() && calcScore(item?.points)
 | 
			
		||||
        } else if (item?.pointType == 1) {//每个选项都有对应分值
 | 
			
		||||
          item?.options?.map(op => {
 | 
			
		||||
            if (typeof field.fieldValue == "object") {
 | 
			
		||||
              if (field.fieldValue?.includes(op.label)) {
 | 
			
		||||
                calcScore(op.point)
 | 
			
		||||
              }
 | 
			
		||||
            } else {
 | 
			
		||||
              op.label == field.fieldValue && calcScore(op.point)
 | 
			
		||||
            }
 | 
			
		||||
          })
 | 
			
		||||
        } else if (item?.pointType == 2) {//答对几项得几分,答错不得分
 | 
			
		||||
          item?.options?.some(op => {
 | 
			
		||||
            if (typeof field.fieldValue == "object") {
 | 
			
		||||
              if (field.fieldValue?.includes(op.label)) {
 | 
			
		||||
                if (item.answer?.includes(op.label)) calcScore(op.point)
 | 
			
		||||
                else return current = 0
 | 
			
		||||
              }
 | 
			
		||||
            } else {
 | 
			
		||||
              op.label == field.fieldValue && calcScore(op.point)
 | 
			
		||||
            }
 | 
			
		||||
          })
 | 
			
		||||
        }
 | 
			
		||||
        this.score += current
 | 
			
		||||
        //打印每题打分
 | 
			
		||||
        if (!!field.fieldValue) {
 | 
			
		||||
          const typeResult = (reply, answer) => {
 | 
			
		||||
            console.log("题目:%s,回答:%s,得分:%s,总分:%s \n 答案:%s", field.fieldName,
 | 
			
		||||
                reply, current, this.score, answer)
 | 
			
		||||
          }
 | 
			
		||||
          typeResult(field.fieldValue?.toString(), item.answer?.toString())
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
    checkForm() {
 | 
			
		||||
      if (this.isPreview) {
 | 
			
		||||
        this.checkUser = true
 | 
			
		||||
        return Promise.resolve()
 | 
			
		||||
      }
 | 
			
		||||
      let {query: {id}, hash} = this.$route,
 | 
			
		||||
          {openId} = this.openUser
 | 
			
		||||
      if (hash != "#form") {
 | 
			
		||||
        this.result = {
 | 
			
		||||
          tips: "非法的调查问卷链接",
 | 
			
		||||
          status: "error"
 | 
			
		||||
        }
 | 
			
		||||
      } else if (openId) {
 | 
			
		||||
        return new Promise(resolve => {
 | 
			
		||||
          this.$http.post("/app/appquestionnairetemplate/commitCheck", null, {
 | 
			
		||||
            params: {id, openId}
 | 
			
		||||
          }).then(res => {
 | 
			
		||||
            if (res?.code == 0) {
 | 
			
		||||
              this.checkUser = true
 | 
			
		||||
              if (this.isResult && res?.data) {
 | 
			
		||||
                this.form = res?.data
 | 
			
		||||
              } else resolve()
 | 
			
		||||
            } else this.result = {
 | 
			
		||||
              tips: "调查问卷加载失败",
 | 
			
		||||
              status: "error",
 | 
			
		||||
              btn: "重新加载",
 | 
			
		||||
              btnTap() {
 | 
			
		||||
                location.reload()
 | 
			
		||||
              }
 | 
			
		||||
            }
 | 
			
		||||
          }).catch(err => {
 | 
			
		||||
            this.result = {
 | 
			
		||||
              tips: err || "调查问卷加载失败",
 | 
			
		||||
            }
 | 
			
		||||
          })
 | 
			
		||||
        })
 | 
			
		||||
      } else {
 | 
			
		||||
        this.getUserInfo().then(() => {
 | 
			
		||||
          if (!!this.openUser?.openId) {
 | 
			
		||||
            this.checkForm()?.then(() => this.checkUser && this.getForm())
 | 
			
		||||
          } else {
 | 
			
		||||
            this.result = {
 | 
			
		||||
              tips: "您的信息获取失败",
 | 
			
		||||
              status: "error",
 | 
			
		||||
              btn: "重新加载",
 | 
			
		||||
              btnTap() {
 | 
			
		||||
                location.reload()
 | 
			
		||||
              }
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        })
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  created() {
 | 
			
		||||
    this.checkForm()?.then(() => this.checkUser && this.getForm())
 | 
			
		||||
  },
 | 
			
		||||
  mounted() {
 | 
			
		||||
    document.title = this.form.title || "调查问卷"
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
.formDetail {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-direction: column;
 | 
			
		||||
  background: #fff;
 | 
			
		||||
 | 
			
		||||
  .headPicture {
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    height: 320px;
 | 
			
		||||
 | 
			
		||||
    .img {
 | 
			
		||||
      width: 100%;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .title {
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    display: flex;
 | 
			
		||||
    justify-content: center;
 | 
			
		||||
    align-items: center;
 | 
			
		||||
    flex-wrap: wrap;
 | 
			
		||||
    padding: 32px;
 | 
			
		||||
    box-sizing: border-box;
 | 
			
		||||
    font-size: 34px;
 | 
			
		||||
    font-weight: bold;
 | 
			
		||||
    color: #333;
 | 
			
		||||
    line-height: 48px;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .bottom {
 | 
			
		||||
    position: fixed;
 | 
			
		||||
    bottom: 0;
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    padding: 32px;
 | 
			
		||||
    box-sizing: border-box;
 | 
			
		||||
    background: #fff;
 | 
			
		||||
    z-index: 99;
 | 
			
		||||
 | 
			
		||||
    .bottomBtn {
 | 
			
		||||
      width: 100%;
 | 
			
		||||
      line-height: 96px;
 | 
			
		||||
      background: #287DE1;
 | 
			
		||||
      color: #fff;
 | 
			
		||||
      text-align: center;
 | 
			
		||||
      height: 96px;
 | 
			
		||||
      font-size: 32px;
 | 
			
		||||
      font-weight: bold;
 | 
			
		||||
      border-radius: 8px;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .tableExplain {
 | 
			
		||||
    font-size: 28px;
 | 
			
		||||
    font-weight: 400;
 | 
			
		||||
    color: #666;
 | 
			
		||||
    padding: 32px 24px;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ::v-deep .u-form-item {
 | 
			
		||||
    .u-form-item--left {
 | 
			
		||||
      font-size: 30px;
 | 
			
		||||
      font-weight: bold;
 | 
			
		||||
      color: #333;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .u-form-item--right__content__slot > * {
 | 
			
		||||
      width: 100%;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .display {
 | 
			
		||||
      justify-content: space-between;
 | 
			
		||||
      min-height: 58px;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .uni-radio-input, .uni-checkbox-input {
 | 
			
		||||
      height: 32px;
 | 
			
		||||
      width: 32px;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .label {
 | 
			
		||||
      flex-shrink: 0;
 | 
			
		||||
 | 
			
		||||
      * + & {
 | 
			
		||||
        margin-left: 16px;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .option {
 | 
			
		||||
      width: 100%;
 | 
			
		||||
      margin-right: 16px;
 | 
			
		||||
      margin-bottom: 16px;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .content {
 | 
			
		||||
    padding: 64px 32px 200px;
 | 
			
		||||
    background: #fff;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ::v-deep .scorePane {
 | 
			
		||||
    width: calc(100% - 40px);
 | 
			
		||||
    padding: 0 32px;
 | 
			
		||||
    height: 124px;
 | 
			
		||||
    background: #E9F2FF;
 | 
			
		||||
    border-radius: 16px;
 | 
			
		||||
    font-size: 30px;
 | 
			
		||||
    font-weight: 500;
 | 
			
		||||
    color: #333333;
 | 
			
		||||
    margin-top: 48px;
 | 
			
		||||
    box-sizing: border-box;
 | 
			
		||||
 | 
			
		||||
    .fill {
 | 
			
		||||
      text-align: center;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    em {
 | 
			
		||||
      font-size: 48px;
 | 
			
		||||
      font-weight: bold;
 | 
			
		||||
      color: #2C72FE;
 | 
			
		||||
      font-style: normal;
 | 
			
		||||
      margin-right: 8px;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										164
									
								
								src/pages/askForm/formList.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,164 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <section class="formList">
 | 
			
		||||
    <ai-top-fixed>
 | 
			
		||||
      <u-search placeholder="请输入标题" :show-action="false" search-icon-color="#ccc"
 | 
			
		||||
                v-model="search.title" @search="page.current=1,getList()"/>
 | 
			
		||||
 | 
			
		||||
    </ai-top-fixed>
 | 
			
		||||
    <div class="mainPane">
 | 
			
		||||
      <div class="formBox column" flex v-for="op in list" :key="op.id">
 | 
			
		||||
        <div flex>
 | 
			
		||||
          <div class="fill column" flex>
 | 
			
		||||
            <b class="title">{{ op.title }}</b>
 | 
			
		||||
            <div class="info wrap" flex>
 | 
			
		||||
              <span v-html="op.createUserName"/>
 | 
			
		||||
              <span v-html="op.createUnitName"/>
 | 
			
		||||
              <span v-html="op.createTime"/>
 | 
			
		||||
              <span v-html="$dict.getLabel('questionnaireType',op.type)"/>
 | 
			
		||||
            </div>
 | 
			
		||||
          </div>
 | 
			
		||||
          <div class="split"/>
 | 
			
		||||
          <div flex class="column submitCount">
 | 
			
		||||
            <b>{{ op.dataCount }}</b>
 | 
			
		||||
            <div>答卷数量</div>
 | 
			
		||||
          </div>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div flex class="bottom">
 | 
			
		||||
          <div class="dot" :style="{background:$dict.getColor('questionnaireStatus',op.status)}"/>
 | 
			
		||||
          <div>{{ $dict.getLabel("questionnaireStatus", op.status) }}</div>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
  </section>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import AiTopFixed from "../../components/AiTopFixed";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: "formList",
 | 
			
		||||
  components: {AiTopFixed},
 | 
			
		||||
  data() {
 | 
			
		||||
    return {
 | 
			
		||||
      page: {current: 1, size: 10, total: 0},
 | 
			
		||||
      search: {title: ""},
 | 
			
		||||
      list: []
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    getList() {
 | 
			
		||||
      this.$http.post("/app/appquestionnairetemplate/list", null, {
 | 
			
		||||
        params: {...this.page, ...this.search}
 | 
			
		||||
      }).then(res => {
 | 
			
		||||
        if (res?.data) {
 | 
			
		||||
          if (this.page.current > 1) {
 | 
			
		||||
            this.list = [...this.list, ...res.data.records]
 | 
			
		||||
          } else this.list = res.data.records
 | 
			
		||||
          this.page.total = res.data.total
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
    reachBottom() {
 | 
			
		||||
      if (this.page.total > this.list.length) {
 | 
			
		||||
        this.page.current++
 | 
			
		||||
        this.getList()
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  created() {
 | 
			
		||||
    this.$dict.load("questionnaireStatus", 'questionnaireType')
 | 
			
		||||
    this.getList()
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
.formList {
 | 
			
		||||
  min-height: 100%;
 | 
			
		||||
  background: #F3F6F9;
 | 
			
		||||
 | 
			
		||||
  ::v-deep .mainPane {
 | 
			
		||||
    padding: 24px 24px 126px;
 | 
			
		||||
 | 
			
		||||
    .formBox {
 | 
			
		||||
      width: 100%;
 | 
			
		||||
      min-height: 220px;
 | 
			
		||||
      background: #FFFFFF;
 | 
			
		||||
      border-radius: 16px;
 | 
			
		||||
      padding: 24px;
 | 
			
		||||
      box-sizing: border-box;
 | 
			
		||||
      text-align: center;
 | 
			
		||||
      color: #999;
 | 
			
		||||
      font-size: 20px;
 | 
			
		||||
      margin-bottom: 24px;
 | 
			
		||||
 | 
			
		||||
      & > div {
 | 
			
		||||
        width: 100%;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      b {
 | 
			
		||||
        width: 100%;
 | 
			
		||||
        white-space: nowrap;
 | 
			
		||||
        overflow: hidden;
 | 
			
		||||
        text-overflow: ellipsis;
 | 
			
		||||
        font-size: 32px;
 | 
			
		||||
        color: #333;
 | 
			
		||||
        margin-bottom: 16px;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .title {
 | 
			
		||||
        text-align: start;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .info {
 | 
			
		||||
        width: 100%;
 | 
			
		||||
 | 
			
		||||
        span {
 | 
			
		||||
          white-space: nowrap;
 | 
			
		||||
          padding: 0 16px;
 | 
			
		||||
          box-sizing: border-box;
 | 
			
		||||
          border-left: 1px solid #D1D2D5;
 | 
			
		||||
          margin-bottom: 4px;
 | 
			
		||||
 | 
			
		||||
          &:first-of-type {
 | 
			
		||||
            border-left: none;
 | 
			
		||||
            padding-left: 0;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .bottom {
 | 
			
		||||
        margin-top: 30px;
 | 
			
		||||
        font-size: 26px;
 | 
			
		||||
 | 
			
		||||
        .dot {
 | 
			
		||||
          width: 11px;
 | 
			
		||||
          height: 11px;
 | 
			
		||||
          background: #3CB300;
 | 
			
		||||
          border-radius: 50%;
 | 
			
		||||
          margin-right: 8px;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .submitCount {
 | 
			
		||||
        width: 118px;
 | 
			
		||||
 | 
			
		||||
        b {
 | 
			
		||||
          color: #1EA0FA;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        & > div {
 | 
			
		||||
          font-size: 22px;
 | 
			
		||||
          white-space: nowrap;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .split {
 | 
			
		||||
        width: 2px;
 | 
			
		||||
        background: #f5f5f5;
 | 
			
		||||
        margin: 0 24px;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										314
									
								
								src/pages/askForm/formSetting.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,314 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="form-setting">
 | 
			
		||||
    <h2>表单设置</h2>
 | 
			
		||||
    <div class="form-setting__list">
 | 
			
		||||
      <div class="setting-item">
 | 
			
		||||
        <div class="setting-item__left">
 | 
			
		||||
          <span>截止时间</span>
 | 
			
		||||
          <image :src="`${$cdn}askform/bz.png`" @click="tips = '表单截止后,用户打开表单会提示此表单已结束' , isShowModal = true" />
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="setting-item__right">
 | 
			
		||||
          <u-radio-group v-model="periodValidityType" active-color="#1088F9">
 | 
			
		||||
            <u-radio name="0">永久有效</u-radio>
 | 
			
		||||
            <u-radio name="1">自定义时间</u-radio>
 | 
			
		||||
          </u-radio-group>
 | 
			
		||||
          <u-icon name="arrow-right" color="#E1E2E3" />
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="setting-item" v-if="periodValidityType === '1'" @click="isShowTime = true">
 | 
			
		||||
        <div class="setting-item__left">
 | 
			
		||||
          <span>截至时间</span>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="setting-item__right">
 | 
			
		||||
          <span>{{ periodValidityEndTime }}</span>
 | 
			
		||||
          <u-icon name="arrow-right" color="#E1E2E3" />
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="setting-item">
 | 
			
		||||
        <div class="setting-item__left">
 | 
			
		||||
          <span>匹配客户方式</span>
 | 
			
		||||
          <image :src="`${$cdn}askform/bz.png`" @click="tips = '将参与活动的微信客户和企业微信客户匹配' , isShowModal = true" />
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="setting-item__right">
 | 
			
		||||
          <span>客户微信ID匹配</span>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="setting-item">
 | 
			
		||||
        <div class="setting-item__left">
 | 
			
		||||
          <span>提交次数</span>
 | 
			
		||||
          <image :src="`${$cdn}askform/bz.png`" @click="tips = '此功能发布后不可修改' , isShowModal = true" />
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="setting-item__right">
 | 
			
		||||
          <u-radio-group v-model="commitType" active-color="#1088F9">
 | 
			
		||||
            <u-radio name="0">不限次数</u-radio>
 | 
			
		||||
            <u-radio name="1">限提交一次</u-radio>
 | 
			
		||||
          </u-radio-group>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="setting-item">
 | 
			
		||||
        <div class="setting-item__left">
 | 
			
		||||
          <span>行为通知</span>
 | 
			
		||||
          <image :src="`${$cdn}askform/bz.png`" @click="tips = '当客户点击或者发布表单时,发送表单的员工将会受到消息提醒' , isShowModal = true" />
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="setting-item__right">
 | 
			
		||||
          <u-switch v-model="actionNotice" active-value="1" inactive-value="0" :size="40" active-color="#1088F9"></u-switch>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="setting-item">
 | 
			
		||||
        <div class="setting-item__left">
 | 
			
		||||
          <span>动态通知</span>
 | 
			
		||||
          <image :src="`${$cdn}askform/bz.png`" @click="tips = '当客户点击或者发布表单时,会将客户的打开行为记录在客户动态里' , isShowModal = true" />
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="setting-item__right">
 | 
			
		||||
          <u-switch v-model="dynamicNotice" active-value="1" inactive-value="0" :size="40" active-color="#1088F9"></u-switch>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="add-form__footer">
 | 
			
		||||
      <div @click="back">
 | 
			
		||||
        <span>取消</span>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div @click="confirm">{{ type === 'edit' ? '发布' : '确定' }}</div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <u-modal v-model="isShowModal" :content="tips"></u-modal>
 | 
			
		||||
    <u-picker mode="time" v-model="isShowTime" :show-time-tag="true" @confirm="onTimeChange" :params="params"></u-picker>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
export default {
 | 
			
		||||
  data () {
 | 
			
		||||
    return {
 | 
			
		||||
      params: {
 | 
			
		||||
        year: true,
 | 
			
		||||
        month: true,
 | 
			
		||||
        day: true,
 | 
			
		||||
        hour: true,
 | 
			
		||||
        minute: true,
 | 
			
		||||
        second: true
 | 
			
		||||
      },
 | 
			
		||||
      tips: '',
 | 
			
		||||
      isShowModal: false,
 | 
			
		||||
      actionNotice: true,
 | 
			
		||||
      dynamicNotice: true,
 | 
			
		||||
      commitType: '1',
 | 
			
		||||
      wechatId: '0',
 | 
			
		||||
      periodValidityEndTime: '',
 | 
			
		||||
      isShowTime: false,
 | 
			
		||||
      periodValidityType: '0',
 | 
			
		||||
      type: '',
 | 
			
		||||
      id: ''
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  onLoad (query) {
 | 
			
		||||
    if (query.id) {
 | 
			
		||||
      this.id = query.id
 | 
			
		||||
      this.getInfo(query.id)
 | 
			
		||||
      this.type = query.type
 | 
			
		||||
    } else if (query.formConfig && query.formConfig !== '{}') {
 | 
			
		||||
      const res = JSON.parse(query.formConfig)
 | 
			
		||||
      this.periodValidityType = res.periodValidityType
 | 
			
		||||
      this.commitType = res.commitType
 | 
			
		||||
      this.actionNotice = res.actionNotice === '1'
 | 
			
		||||
      this.dynamicNotice = res.dynamicNotice === '1'
 | 
			
		||||
 | 
			
		||||
      if (res.periodValidityType === '1') {
 | 
			
		||||
        this.periodValidityEndTime = res.periodValidityEndTime
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  methods: {
 | 
			
		||||
    onTimeChange (e) {
 | 
			
		||||
      this.periodValidityEndTime = `${e.year}-${e.month}-${e.day} ${e.hour}:${e.minute}:${e.second}`
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    back () {
 | 
			
		||||
      uni.navigateBack({
 | 
			
		||||
        delta: 1
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    getInfo (id) {
 | 
			
		||||
      this.$http.post(`/app/appquestionnairetemplate/queryDetailById?id=${id}`).then(res => {
 | 
			
		||||
        if (res.code == 0) {
 | 
			
		||||
          this.periodValidityType = res.data.periodValidityType
 | 
			
		||||
          this.commitType = res.data.commitType
 | 
			
		||||
          this.actionNotice = res.data.actionNotice === '1'
 | 
			
		||||
          this.dynamicNotice = res.data.dynamicNotice === '1'
 | 
			
		||||
 | 
			
		||||
          if (res.data.periodValidityType === '1') {
 | 
			
		||||
            this.periodValidityEndTime = res.data.periodValidityEndTime
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }).catch(msg => {
 | 
			
		||||
        this.$u.toast(msg)
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    publish () {
 | 
			
		||||
      this.$http.post(`/app/appquestionnairetemplate/release`, null, {
 | 
			
		||||
        params: {
 | 
			
		||||
          commitType: this.commitType,
 | 
			
		||||
          periodValidityType: this.periodValidityType,
 | 
			
		||||
          actionNotice: this.actionNotice ? '1' : '0',
 | 
			
		||||
          dynamicNotice: this.dynamicNotice ? '1' : '0',
 | 
			
		||||
          shareStatus: '0',
 | 
			
		||||
          wechatId: '0',
 | 
			
		||||
          id: this.id,
 | 
			
		||||
          periodValidityEndTime: this.periodValidityType === '1' ? this.periodValidityEndTime : ''
 | 
			
		||||
        }
 | 
			
		||||
      }).then(res => {
 | 
			
		||||
        if (res.code == 0) {
 | 
			
		||||
          uni.$emit('reload')
 | 
			
		||||
          this.$u.toast('发布成功')
 | 
			
		||||
 | 
			
		||||
          this.back()
 | 
			
		||||
        }
 | 
			
		||||
      }).catch(e => {
 | 
			
		||||
        this.$u.toast(e)
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    confirm () {
 | 
			
		||||
      if (this.type === 'edit') {
 | 
			
		||||
        this.publish()
 | 
			
		||||
 | 
			
		||||
        return false
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      uni.$emit('setting', {
 | 
			
		||||
        periodValidityType: this.periodValidityType,
 | 
			
		||||
        commitType: this.commitType,
 | 
			
		||||
        actionNotice: this.actionNotice ? '1' : '0',
 | 
			
		||||
        dynamicNotice: this.dynamicNotice ? '1' : '0',
 | 
			
		||||
        periodValidityEndTime: this.periodValidityEndTime ? this.periodValidityEndTime : ''
 | 
			
		||||
      })
 | 
			
		||||
 | 
			
		||||
      this.back()
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
  .form-setting {
 | 
			
		||||
    padding: 0 20px;
 | 
			
		||||
 | 
			
		||||
    .add-form__footer {
 | 
			
		||||
      display: flex;
 | 
			
		||||
      align-items: center;
 | 
			
		||||
      position: fixed;
 | 
			
		||||
      left: 0;
 | 
			
		||||
      bottom: 0;
 | 
			
		||||
      z-index: 1;
 | 
			
		||||
      width: 100%;
 | 
			
		||||
      height: 112px;
 | 
			
		||||
      text-align: center;
 | 
			
		||||
 | 
			
		||||
      div {
 | 
			
		||||
        display: flex;
 | 
			
		||||
        align-items: center;
 | 
			
		||||
        justify-content: center;
 | 
			
		||||
        flex: 1;
 | 
			
		||||
        height: 100%;
 | 
			
		||||
        text-align: center;
 | 
			
		||||
        background: #fff;
 | 
			
		||||
 | 
			
		||||
        &:first-child:active {
 | 
			
		||||
          background: #eee;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        &:last-child {
 | 
			
		||||
          color: #fff;
 | 
			
		||||
          font-size: 36px;
 | 
			
		||||
          background: #3192F4;
 | 
			
		||||
 | 
			
		||||
          &:active {
 | 
			
		||||
            opacity: 0.8;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        span {
 | 
			
		||||
          flex: 1;
 | 
			
		||||
          height: 100%;
 | 
			
		||||
          line-height: 112px;
 | 
			
		||||
          color: #333333;
 | 
			
		||||
          font-size: 32px;
 | 
			
		||||
 | 
			
		||||
          &:active {
 | 
			
		||||
            background: #eee;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    * {
 | 
			
		||||
      box-sizing: border-box;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    & > h2 {
 | 
			
		||||
      height: 80px;
 | 
			
		||||
      padding-top: 24px;
 | 
			
		||||
      font-size: 28px;
 | 
			
		||||
      color: #999999;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .form-setting__list {
 | 
			
		||||
      padding: 0 20px;
 | 
			
		||||
      background: #fff;
 | 
			
		||||
      border-radius: 8px;
 | 
			
		||||
 | 
			
		||||
      .setting-item {
 | 
			
		||||
        display: flex;
 | 
			
		||||
        align-items: center;
 | 
			
		||||
        justify-content: space-between;
 | 
			
		||||
        height: 104px;
 | 
			
		||||
        border-bottom: 1px solid #D8DDE6;
 | 
			
		||||
 | 
			
		||||
        .setting-item__right {
 | 
			
		||||
          color: #999;
 | 
			
		||||
          font-size: 28px;
 | 
			
		||||
 | 
			
		||||
          span {
 | 
			
		||||
            margin-right: 6px;
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          ::v-deep .u-radio__label {
 | 
			
		||||
            color: #999;
 | 
			
		||||
            font-size: 28px;
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          ::v-deep .u-radio {
 | 
			
		||||
            &:last-child {
 | 
			
		||||
              .u-radio__label {
 | 
			
		||||
                margin-right: 6px;
 | 
			
		||||
              }
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        &:last-child {
 | 
			
		||||
          border: none;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        & > div {
 | 
			
		||||
          display: flex;
 | 
			
		||||
          align-items: center;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .setting-item__left {
 | 
			
		||||
          color: #666666;
 | 
			
		||||
          font-size: 30px;
 | 
			
		||||
 | 
			
		||||
          image {
 | 
			
		||||
            width: 30px;
 | 
			
		||||
            height: 30px;
 | 
			
		||||
            margin-left: 16px;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										69
									
								
								src/pages/askForm/index.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,69 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="form">
 | 
			
		||||
    <div class="form-content">
 | 
			
		||||
      <add-list ref="addList" v-if="currIndex === 1"></add-list>
 | 
			
		||||
      <list ref="list" v-if="currIndex === 0"></list>
 | 
			
		||||
    </div>
 | 
			
		||||
    <ai-tabbar :active.sync="currIndex" :list="tabBar"/>
 | 
			
		||||
    <div class="form-footer"></div>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import addList from './components/addList.vue'
 | 
			
		||||
import list from './components/list.vue'
 | 
			
		||||
import AiTabbar from '../../components/AiTabbar'
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: 'formIndex',
 | 
			
		||||
  label: '问卷表单',
 | 
			
		||||
 | 
			
		||||
  data () {
 | 
			
		||||
    return {
 | 
			
		||||
      currIndex: 0
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  components: {
 | 
			
		||||
    addList,
 | 
			
		||||
    AiTabbar,
 | 
			
		||||
    list
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  computed: {
 | 
			
		||||
    tabBar () {
 | 
			
		||||
      const link = icon => `${this.$cdn}askform/${icon}.png`
 | 
			
		||||
      return [
 | 
			
		||||
        {text: "表单列表", iconPath: "bdlb1", selectedIconPath: "bdlb2" },
 | 
			
		||||
        {text: "新建项目", iconPath: "xjxm1", selectedIconPath: "xjxm2" }
 | 
			
		||||
      ].map(e => ({
 | 
			
		||||
        ...e,
 | 
			
		||||
        iconPath: link(e.iconPath),
 | 
			
		||||
        selectedIconPath: link(e.selectedIconPath)
 | 
			
		||||
      }))
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  onLoad () {
 | 
			
		||||
    uni.$on('reload', () => {
 | 
			
		||||
      if (this.currIndex === 0) {
 | 
			
		||||
        this.$refs.list.reload()
 | 
			
		||||
      } else {
 | 
			
		||||
        this.$refs.addList.getList()
 | 
			
		||||
      }
 | 
			
		||||
    })
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  onReachBottom() {
 | 
			
		||||
    if (this.currIndex === 0) {
 | 
			
		||||
      this.$refs.list.getList()
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
  .form {
 | 
			
		||||
    padding-bottom: 98px;
 | 
			
		||||
  }
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										457
									
								
								src/pages/askForm/previewForm.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,457 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="add-form">
 | 
			
		||||
    <div class="header-pic">
 | 
			
		||||
      <image v-if="form.headPicture" :src="form.headPicture" />
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="form-info">
 | 
			
		||||
      <div class="form-info__wrapper">
 | 
			
		||||
        <textarea class="title" :auto-height="true" disabled placeholder="请输入标题 (必填)" v-model="form.title"></textarea>
 | 
			
		||||
        <u-input class="content" disabled :clearable="false" type="textarea" v-model="form.tableExplain" placeholder="请输入表单描述 (选填)" :height="80" :auto-height="true" :maxlength="255"></u-input>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="components-list">
 | 
			
		||||
      <div class="components-item" v-for="(item, index) in targetList" :key="index">
 | 
			
		||||
        <div class="components-item__title">
 | 
			
		||||
          <div class="components-item__title--left">
 | 
			
		||||
            <em :style="{opacity: item.required ? 1 : 0}">*</em>
 | 
			
		||||
            <i>{{ index + 1 }}.</i>
 | 
			
		||||
            <h2>{{ item.label }}</h2>
 | 
			
		||||
          </div>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="components-item__filed">
 | 
			
		||||
          <template v-if="(item.type === 'radio')">
 | 
			
		||||
            <u-radio-group v-model="item.value" wrap>
 | 
			
		||||
              <u-radio :name="field.label" v-for="(field, i) in item.options" :key="i">
 | 
			
		||||
                <image :src="field.img[0].url" v-if="field.img.length"/>
 | 
			
		||||
                <span>{{ field.label }}</span>
 | 
			
		||||
              </u-radio>
 | 
			
		||||
            </u-radio-group>
 | 
			
		||||
          </template>
 | 
			
		||||
          <template v-if="(item.type === 'checkbox')">
 | 
			
		||||
            <u-checkbox-group wrap>
 | 
			
		||||
              <u-checkbox :name="field.label" v-model="field.checked1" v-for="(field, i) in item.options" :key="i">
 | 
			
		||||
                <image :src="field.img[0].url" v-if="field.img.length"/>
 | 
			
		||||
                <span>{{ field.label }}</span>
 | 
			
		||||
              </u-checkbox>
 | 
			
		||||
            </u-checkbox-group>
 | 
			
		||||
          </template>
 | 
			
		||||
          <template v-if="(item.type === 'select')">
 | 
			
		||||
            <div class="components-item__select">
 | 
			
		||||
              <span>{{ item.placeholder }}</span>
 | 
			
		||||
              <u-icon name="arrow-down" color="#DEDFDF" />
 | 
			
		||||
            </div>
 | 
			
		||||
          </template>
 | 
			
		||||
          <template v-if="(item.type === 'upload')">
 | 
			
		||||
            <div class="components-item__select components-item__textarea components-item__upload">
 | 
			
		||||
              <image :src="`${$cdn}askform/upload.png`" />
 | 
			
		||||
              <span>选择图片(2M以内)</span>
 | 
			
		||||
            </div>
 | 
			
		||||
          </template>
 | 
			
		||||
          <template v-if="(item.type === 'input')">
 | 
			
		||||
            <div class="components-item__select">
 | 
			
		||||
              <span>{{ item.placeholder }}</span>
 | 
			
		||||
            </div>
 | 
			
		||||
          </template>
 | 
			
		||||
          <template v-if="(item.type === 'textarea')">
 | 
			
		||||
            <div class="components-item__select components-item__textarea">
 | 
			
		||||
              <span>{{ item.placeholder }}</span>
 | 
			
		||||
            </div>
 | 
			
		||||
          </template>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <AiBack></AiBack>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
  import AiBack from "@/components/AiBack";
 | 
			
		||||
  export default {
 | 
			
		||||
    data () {
 | 
			
		||||
      return {
 | 
			
		||||
        form: {
 | 
			
		||||
          tableExplain: '详细描述',
 | 
			
		||||
          title: '问卷调查',
 | 
			
		||||
          isShowheadPicture: true,
 | 
			
		||||
          isShowTableExplain: true,
 | 
			
		||||
          isShowBtn: true,
 | 
			
		||||
          headPicture: '',
 | 
			
		||||
          commitType: '1',
 | 
			
		||||
          periodValidityType: '0',
 | 
			
		||||
          actionNotice: '1',
 | 
			
		||||
          dynamicNotice: '1',
 | 
			
		||||
          periodValidityEndTime: '',
 | 
			
		||||
          shareStatus: '0',
 | 
			
		||||
          count: 0,
 | 
			
		||||
          wechatId: '0',
 | 
			
		||||
          type: 0,
 | 
			
		||||
          buttonExplain: '提交',
 | 
			
		||||
          tips: true
 | 
			
		||||
        },
 | 
			
		||||
        templateType: 0,
 | 
			
		||||
        targetList: [],
 | 
			
		||||
        isShow: false,
 | 
			
		||||
        type: 0,
 | 
			
		||||
        id: '',
 | 
			
		||||
        touchStart: 0
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    onLoad (query) {
 | 
			
		||||
      this.form = JSON.parse(query.form)
 | 
			
		||||
      this.targetList = JSON.parse(query.targetList)
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    components: {
 | 
			
		||||
      AiBack
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    methods: {
 | 
			
		||||
      getInfo (id) {
 | 
			
		||||
        uni.showLoading()
 | 
			
		||||
        this.$http.post(`/app/appquestionnairetemplate/queryDetailById?id=${id}`).then(res => {
 | 
			
		||||
          if (res.code == 0) {
 | 
			
		||||
            this.form = {
 | 
			
		||||
              ...res.data,
 | 
			
		||||
              headPicture: res.data.headPicture
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            this.type = res.data.type
 | 
			
		||||
 | 
			
		||||
            this.targetList = res.data.fields.map(item => {
 | 
			
		||||
              return JSON.parse(item.fieldInfo)
 | 
			
		||||
            })
 | 
			
		||||
 | 
			
		||||
            this.pageShow = true
 | 
			
		||||
          } else {
 | 
			
		||||
            this.$u.toast(res.msg)
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          uni.hideLoading()
 | 
			
		||||
        }).catch(() => {
 | 
			
		||||
          uni.hideLoading()
 | 
			
		||||
        })
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
  .add-form {
 | 
			
		||||
    min-height: 100vh;
 | 
			
		||||
    padding-bottom: 60px;
 | 
			
		||||
    box-sizing: border-box;
 | 
			
		||||
    background: #F3F6F9;
 | 
			
		||||
 | 
			
		||||
    * {
 | 
			
		||||
      box-sizing: border-box;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ::v-deep .u-drawer-bottom {
 | 
			
		||||
      background-color: transparent;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .components-list {
 | 
			
		||||
      padding: 0 20px;
 | 
			
		||||
 | 
			
		||||
      .components-item {
 | 
			
		||||
        margin-top: 24px;
 | 
			
		||||
        padding: 32px;
 | 
			
		||||
        box-shadow: 0 4px 8px 4px rgba(233, 233, 233, 0.39);
 | 
			
		||||
        border-radius: 8px;
 | 
			
		||||
        overflow: hidden;
 | 
			
		||||
        border: 1px solid #EEEFF0;
 | 
			
		||||
        background: #fff;
 | 
			
		||||
 | 
			
		||||
        ::v-deep .u-radio, ::v-deep .u-checkbox {
 | 
			
		||||
          position: relative;
 | 
			
		||||
          margin-bottom: 20px;
 | 
			
		||||
 | 
			
		||||
          &:last-child {
 | 
			
		||||
            margin-bottom: 0;
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          .u-checkbox__icon-wrap, .u-radio__icon-wrap {
 | 
			
		||||
            position: absolute;
 | 
			
		||||
            top: 4px;
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          .u-radio__label, .u-checkbox__label {
 | 
			
		||||
            display: flex;
 | 
			
		||||
            align-items: center;
 | 
			
		||||
            margin-right: 0;
 | 
			
		||||
            margin-left: 40px;
 | 
			
		||||
            line-height: 1.5;
 | 
			
		||||
            text-align: justify;
 | 
			
		||||
 | 
			
		||||
            image {
 | 
			
		||||
              width: 100px;
 | 
			
		||||
              height: 100px;
 | 
			
		||||
              margin: 0 10px;
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
        span {
 | 
			
		||||
          flex: 1;
 | 
			
		||||
          color: #666;
 | 
			
		||||
          font-size: 26px;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .components-item__select {
 | 
			
		||||
          display: flex;
 | 
			
		||||
          align-items: center;
 | 
			
		||||
          justify-content: space-between;
 | 
			
		||||
          width: 100%;
 | 
			
		||||
          height: 80px;
 | 
			
		||||
          margin-bottom: 8px;
 | 
			
		||||
          padding: 0 26px;
 | 
			
		||||
          border: 1px solid #DEDFDF;
 | 
			
		||||
 | 
			
		||||
          &.components-item__textarea {
 | 
			
		||||
            align-items: flex-start;
 | 
			
		||||
            height: 160px;
 | 
			
		||||
            padding-top: 20px;
 | 
			
		||||
 | 
			
		||||
            image {
 | 
			
		||||
              width: 46px;
 | 
			
		||||
              height: 34px;
 | 
			
		||||
              margin-right: 16px;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            span {
 | 
			
		||||
              color: #666;
 | 
			
		||||
              font-size: 26px;
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          &.components-item__upload {
 | 
			
		||||
            justify-content: center;
 | 
			
		||||
            align-items: center;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .components-item__title {
 | 
			
		||||
          display: flex;
 | 
			
		||||
          justify-content: space-between;
 | 
			
		||||
          margin-bottom: 32px;
 | 
			
		||||
 | 
			
		||||
          em {
 | 
			
		||||
            margin-right: 4px;
 | 
			
		||||
            font-style: normal;
 | 
			
		||||
            color: rgb(226, 33, 32);;
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          image {
 | 
			
		||||
            width: 32px;
 | 
			
		||||
            height: 32px;
 | 
			
		||||
            box-sizing: content-box;
 | 
			
		||||
            padding: 20px 0 20px 20px;
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          div {
 | 
			
		||||
            display: flex;
 | 
			
		||||
            align-items: baseline;
 | 
			
		||||
            color: #333333;
 | 
			
		||||
            font-size: 32px;
 | 
			
		||||
 | 
			
		||||
            i {
 | 
			
		||||
              font-style: normal;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            h2 {
 | 
			
		||||
              font-weight: 600;
 | 
			
		||||
              font-size: 32px;
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .add-popup {
 | 
			
		||||
      height: 440px;
 | 
			
		||||
      border-radius: 20px 20px 0 0;
 | 
			
		||||
      background: #fff;
 | 
			
		||||
 | 
			
		||||
      .add-popup__title {
 | 
			
		||||
        display: flex;
 | 
			
		||||
        position: relative;
 | 
			
		||||
        align-items: center;
 | 
			
		||||
        justify-content: center;
 | 
			
		||||
        height: 96px;
 | 
			
		||||
        border-bottom: 1px solid #E4E5E6;
 | 
			
		||||
 | 
			
		||||
        h2 {
 | 
			
		||||
          color: #333333;
 | 
			
		||||
          font-size: 32px;
 | 
			
		||||
          font-weight: 600;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        image {
 | 
			
		||||
          position: absolute;
 | 
			
		||||
          right: 32px;
 | 
			
		||||
          top: 50%;
 | 
			
		||||
          width: 30px;
 | 
			
		||||
          height: 20px;
 | 
			
		||||
          transform: translateY(-50%);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .add-popup__list {
 | 
			
		||||
        display: flex;
 | 
			
		||||
        flex-wrap: wrap;
 | 
			
		||||
        padding: 0 34px;
 | 
			
		||||
 | 
			
		||||
        span {
 | 
			
		||||
          width: calc((100% - 64px) / 3);
 | 
			
		||||
          height: 78px;
 | 
			
		||||
          line-height: 78px;
 | 
			
		||||
          margin-top: 32px;
 | 
			
		||||
          margin-right: 32px;
 | 
			
		||||
          text-align: center;
 | 
			
		||||
          color: #333333;
 | 
			
		||||
          font-size: 28px;
 | 
			
		||||
          border-radius: 8px;
 | 
			
		||||
          border: 1px solid #E4E5E6;
 | 
			
		||||
 | 
			
		||||
          &:nth-of-type(3n) {
 | 
			
		||||
            margin-right: 0;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .add-form__footer {
 | 
			
		||||
      display: flex;
 | 
			
		||||
      align-items: center;
 | 
			
		||||
      position: fixed;
 | 
			
		||||
      left: 0;
 | 
			
		||||
      bottom: 0;
 | 
			
		||||
      z-index: 1;
 | 
			
		||||
      width: 100%;
 | 
			
		||||
      height: 112px;
 | 
			
		||||
      text-align: center;
 | 
			
		||||
 | 
			
		||||
      div {
 | 
			
		||||
        display: flex;
 | 
			
		||||
        align-items: center;
 | 
			
		||||
        justify-content: center;
 | 
			
		||||
        flex: 1;
 | 
			
		||||
        height: 100%;
 | 
			
		||||
        text-align: center;
 | 
			
		||||
        background: #fff;
 | 
			
		||||
 | 
			
		||||
        &:last-child {
 | 
			
		||||
          color: #fff;
 | 
			
		||||
          font-size: 36px;
 | 
			
		||||
          background: #3192F4;
 | 
			
		||||
 | 
			
		||||
          &:active {
 | 
			
		||||
            opacity: 0.8;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        span {
 | 
			
		||||
          flex: 1;
 | 
			
		||||
          height: 100%;
 | 
			
		||||
          line-height: 112px;
 | 
			
		||||
          color: #333333;
 | 
			
		||||
          font-size: 32px;
 | 
			
		||||
 | 
			
		||||
          &:active {
 | 
			
		||||
            background: #eee;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .add-form__btn {
 | 
			
		||||
      display: flex;
 | 
			
		||||
      align-items: center;
 | 
			
		||||
      justify-content: center;
 | 
			
		||||
      width: 214px;
 | 
			
		||||
      height: 66px;
 | 
			
		||||
      line-height: 66px;
 | 
			
		||||
      margin: 64px auto 0;
 | 
			
		||||
      background: #FFFFFF;
 | 
			
		||||
      border-radius: 34px;
 | 
			
		||||
 | 
			
		||||
      &:active {
 | 
			
		||||
        opacity: 0.8;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      image {
 | 
			
		||||
        width: 28px;
 | 
			
		||||
        height: 28px;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      span {
 | 
			
		||||
        margin-left: 16px;
 | 
			
		||||
        color: #4392E6;
 | 
			
		||||
        font-size: 28px;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    * {
 | 
			
		||||
      box-sizing: border-box;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .form-info {
 | 
			
		||||
      margin-top: 26px;
 | 
			
		||||
      padding: 0 20px;
 | 
			
		||||
 | 
			
		||||
      & > h2 {
 | 
			
		||||
        height: 76px;
 | 
			
		||||
        line-height: 76px;
 | 
			
		||||
        color: #999999;
 | 
			
		||||
        font-weight: normal;
 | 
			
		||||
        font-size: 28px;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .form-info__wrapper {
 | 
			
		||||
        padding: 0 18px;
 | 
			
		||||
        background: #fff;
 | 
			
		||||
 | 
			
		||||
        .title {
 | 
			
		||||
          width: 100%;
 | 
			
		||||
          padding: 22px 0;
 | 
			
		||||
          font-size: 36px;
 | 
			
		||||
          border-bottom: 1px solid #F1F2F3;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .content {
 | 
			
		||||
          padding: 30px 0!important;
 | 
			
		||||
          font-size: 28px;
 | 
			
		||||
 | 
			
		||||
          ::v-deep textarea {
 | 
			
		||||
            color: #333;
 | 
			
		||||
            font-size: 28px!important;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .header-pic {
 | 
			
		||||
      position: relative;
 | 
			
		||||
      font-size: 0;
 | 
			
		||||
 | 
			
		||||
      span {
 | 
			
		||||
        position: absolute;
 | 
			
		||||
        bottom: 16px;
 | 
			
		||||
        right: 16px;
 | 
			
		||||
        z-index: 1;
 | 
			
		||||
        width: 148px;
 | 
			
		||||
        height: 56px;
 | 
			
		||||
        line-height: 56px;
 | 
			
		||||
        text-align: center;
 | 
			
		||||
        color: #fff;
 | 
			
		||||
        font-size: 26px;
 | 
			
		||||
        background: rgba(0, 0, 0, 0.16);
 | 
			
		||||
        border-radius: 28px;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      image {
 | 
			
		||||
        width: 100%;
 | 
			
		||||
        height: 320px;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										501
									
								
								src/pages/bigHorn/addPlay.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,501 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="addPlay">
 | 
			
		||||
    <div class="content">
 | 
			
		||||
      <div class="item">
 | 
			
		||||
        <div class="label">播发内容</div>
 | 
			
		||||
        <div class="value" @click="linkTo('/pages/resourcesManage/resourcesManage?isChoose=1')">
 | 
			
		||||
          <span :class="formData.mediaName == '请选择' ? 'color-999' : ''">{{formData.mediaName}}</span>
 | 
			
		||||
          <img src="./img/right-icon.png" alt="">
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="item">
 | 
			
		||||
        <div class="label">播放设备</div>
 | 
			
		||||
        <div class="value" @click="selectClick('showEquipment', equipmentList)">
 | 
			
		||||
          <span :class="formData.serialName == '请选择' ? 'color-999' : ''">{{formData.serialName}}</span>
 | 
			
		||||
          <img src="./img/right-icon.png" alt="">
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="item">
 | 
			
		||||
        <div class="label">播发级别</div>
 | 
			
		||||
        <div class="value" @click="selectClick('showMessageLevel', messageLevelList)">
 | 
			
		||||
          <span :class="formData.messageLevelName == '请选择' ? 'color-999' : ''">{{formData.messageLevelName}}</span>
 | 
			
		||||
          <img src="./img/right-icon.png" alt="">
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="radio-content">
 | 
			
		||||
      <div class="title">播放方式</div>
 | 
			
		||||
      <div class="item mar-r50" :class="formData.taskType == 0 ? 'active' : ''"  @click="formData.taskType = 0">立即播放<img src="./img/bigHorn-xz.png" alt=""></div>
 | 
			
		||||
      <div class="item" :class="formData.taskType == 1 ? 'active' : ''" @click="formData.taskType = 1"><img src="./img/bigHorn-xz.png" alt="">定时播放</div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="content" v-if="formData.taskType != 0">
 | 
			
		||||
      <div class="item">
 | 
			
		||||
        <div class="label">定时策略</div>
 | 
			
		||||
        <div class="value" @click="selectClick('showCyclingType', cyclingTypeList)">
 | 
			
		||||
          <span :class="formData.cyclingTypeName == '请选择' ? 'color-999' : ''">{{formData.cyclingTypeName}}</span>
 | 
			
		||||
          <img src="./img/right-icon.png" alt="">
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="radio-content" v-if="formData.taskType != 0 && formData.cyclingType == 2">
 | 
			
		||||
      <div class="title">播放天数</div>
 | 
			
		||||
      <div class="mini-item" :class="item.isCheck ? 'mini-active' : ''" v-for="(item, index) in dayList" :key="index" @click="checkClick(index)">{{item.label}}</div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="content" v-if="formData.taskType != 0 && formData.cyclingType == 3">
 | 
			
		||||
      <div class="item">
 | 
			
		||||
        <div class="label">播放天数</div>
 | 
			
		||||
        <div class="value">
 | 
			
		||||
          <u-input type="text" placeholder="请输入" height="18" input-align="right" v-model="formData.broadcastDay" maxlength="4" />
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="content" v-if="formData.taskType != 0">
 | 
			
		||||
      <div class="item">
 | 
			
		||||
        <div class="label">开始日期</div>
 | 
			
		||||
        <div class="value" @click="timeClick(true, 'showDate')">
 | 
			
		||||
          <span :class="formData.startDate ? 'color-999' : ''">{{formData.startDate || '请选择'}}</span>
 | 
			
		||||
          <img src="./img/right-icon.png" alt="">
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="item">
 | 
			
		||||
        <div class="label">开始时间</div>
 | 
			
		||||
        <div class="value" @click="timeClick(false, 'showSatrt')">
 | 
			
		||||
          <span :class="formData.startTime ? 'color-999' : ''">{{formData.startTime || '请选择'}}</span>
 | 
			
		||||
          <img src="./img/right-icon.png" alt="">
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="item">
 | 
			
		||||
        <div class="label">结束时间</div>
 | 
			
		||||
        <div class="value" @click="timeClick(false, 'showEnd')">
 | 
			
		||||
          <span :class="formData.endTime ? 'color-999' : ''">{{formData.endTime || '请选择'}}</span>
 | 
			
		||||
          <img src="./img/right-icon.png" alt="">
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="btn" @click="addConfirm">确认</div>
 | 
			
		||||
    <u-select v-model="showSelect" :list="selectList" @confirm="confirm" label-name="dictName" value-name="dictValue"></u-select>
 | 
			
		||||
    <u-picker v-model="showDateTime" mode="time" :params="params" @confirm="confirm"></u-picker>
 | 
			
		||||
    <AiBack></AiBack>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
<script> 
 | 
			
		||||
  import AiBack from "@/components/AiBack";
 | 
			
		||||
export default {
 | 
			
		||||
  name: "addPlay",
 | 
			
		||||
  data() {
 | 
			
		||||
    return {
 | 
			
		||||
      showSelect: false,
 | 
			
		||||
      selectList: [],
 | 
			
		||||
      showMedia: false,
 | 
			
		||||
      mediaList: [],
 | 
			
		||||
      showEquipment: false,
 | 
			
		||||
      equipmentList: [],
 | 
			
		||||
      showMessageLevel: false,
 | 
			
		||||
      messageLevelList: [],
 | 
			
		||||
      showCyclingType: false,
 | 
			
		||||
      cyclingTypeList: [],
 | 
			
		||||
      formData: {
 | 
			
		||||
        mediaId: '',
 | 
			
		||||
        mediaName: '请选择',
 | 
			
		||||
        serialNo: '',
 | 
			
		||||
        serialName: '请选择',
 | 
			
		||||
        messageLevel: '',
 | 
			
		||||
        messageLevelName: '请选择',
 | 
			
		||||
        taskType: '0',
 | 
			
		||||
        cyclingTypeName: '请选择',
 | 
			
		||||
        cyclingType: '',
 | 
			
		||||
        startDate: '',
 | 
			
		||||
        startTime: '',
 | 
			
		||||
        endTime: '',
 | 
			
		||||
        broadcastDay: '',
 | 
			
		||||
        cyclingDate: ''
 | 
			
		||||
      },
 | 
			
		||||
      dayList: [
 | 
			
		||||
        {
 | 
			
		||||
          isCheck: false,
 | 
			
		||||
          value: 1,
 | 
			
		||||
          label: '每周一'
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          isCheck: false,
 | 
			
		||||
          value: 2,
 | 
			
		||||
          label: '每周二'
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          isCheck: false,
 | 
			
		||||
          value: 3,
 | 
			
		||||
          label: '每周三'
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          isCheck: false,
 | 
			
		||||
          value: 4,
 | 
			
		||||
          label: '每周四'
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          isCheck: false,
 | 
			
		||||
          value: 5,
 | 
			
		||||
          label: '每周五'
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          isCheck: false,
 | 
			
		||||
          value: 6,
 | 
			
		||||
          label: '每周六'
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          isCheck: false,
 | 
			
		||||
          value: 7,
 | 
			
		||||
          label: '每周日'
 | 
			
		||||
        }
 | 
			
		||||
      ],
 | 
			
		||||
      showDateTime: false,
 | 
			
		||||
      showDate: false,
 | 
			
		||||
      showSatrt: false,
 | 
			
		||||
      showEnd: false,
 | 
			
		||||
      params: {
 | 
			
		||||
        year: true,
 | 
			
		||||
        month: true,
 | 
			
		||||
        day: true,
 | 
			
		||||
        hour: false,
 | 
			
		||||
        minute: false,
 | 
			
		||||
        second: false
 | 
			
		||||
      },
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  components: {
 | 
			
		||||
    AiBack
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  onLoad () {
 | 
			
		||||
    uni.$on('choose', e => {
 | 
			
		||||
      console.log(e)
 | 
			
		||||
      this.formData.mediaId = e.mediaId
 | 
			
		||||
      this.formData.mediaName = e.mediaName
 | 
			
		||||
    })
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  methods: {
 | 
			
		||||
    addConfirm() {
 | 
			
		||||
      var cyclingDateList = []
 | 
			
		||||
      this.dayList.map((item) => {
 | 
			
		||||
        if(item.isCheck) {
 | 
			
		||||
          cyclingDateList.push(item.value)
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
 | 
			
		||||
      if(!this.formData.mediaId) {
 | 
			
		||||
        return this.$u.toast('请选择播发内容')
 | 
			
		||||
      }
 | 
			
		||||
      if(!this.formData.serialNo) {
 | 
			
		||||
        return this.$u.toast('请选择播放设备')
 | 
			
		||||
      }
 | 
			
		||||
      if(!this.formData.messageLevel) {
 | 
			
		||||
        return this.$u.toast('播发级别')
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      //播放方式(定时播放)
 | 
			
		||||
      if(this.formData.taskType != 0 && this.formData.startDate == '请选择') {
 | 
			
		||||
        return this.$u.toast('请选择开始日期')
 | 
			
		||||
      }
 | 
			
		||||
      if(this.formData.taskType != 0 && this.formData.startTime == '请选择') {
 | 
			
		||||
        return this.$u.toast('请选择开始时间')
 | 
			
		||||
      }
 | 
			
		||||
      if(this.formData.taskType != 0 && this.formData.endTime == '请选择') {
 | 
			
		||||
        return this.$u.toast('请选择结束时间')
 | 
			
		||||
      }
 | 
			
		||||
      //播放方式(定时播放)定时策略(时长)
 | 
			
		||||
      if(this.formData.taskType != 0 && this.formData.cyclingType == 3 && !this.formData.broadcastDay) {
 | 
			
		||||
        return this.$u.toast('请输入播放天数')
 | 
			
		||||
      }
 | 
			
		||||
      //播放方式(定时播放)定时策略(自定义)
 | 
			
		||||
      if(this.formData.taskType != 0 && this.formData.cyclingType == 2 && !cyclingDateList.length) {
 | 
			
		||||
        return this.$u.toast('请选择播放天数')
 | 
			
		||||
      }
 | 
			
		||||
      
 | 
			
		||||
      if(this.formData.taskType != 0 && this.formData.cyclingType == 2) {
 | 
			
		||||
        this.formData.cyclingDate = cyclingDateList.join(',')
 | 
			
		||||
      }
 | 
			
		||||
      this.formData.coverageType = '4'
 | 
			
		||||
      this.$http.post(`/app/appzyvideobroadcast/play`, {...this.formData,}).then((res) => {
 | 
			
		||||
        if (res.code == 0) {
 | 
			
		||||
          this.$u.toast('提交成功')
 | 
			
		||||
          setTimeout(() => {
 | 
			
		||||
            uni.navigateBack()
 | 
			
		||||
          }, 1000)
 | 
			
		||||
        }
 | 
			
		||||
      }) 
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    linkTo (path) {
 | 
			
		||||
      uni.navigateTo({
 | 
			
		||||
        url: path
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    confirm(e) {
 | 
			
		||||
      if(this.showMedia) {
 | 
			
		||||
        this.formData.mediaId = e[0].value
 | 
			
		||||
        this.formData.mediaName = e[0].label
 | 
			
		||||
      }
 | 
			
		||||
      if(this.showEquipment) {
 | 
			
		||||
        this.formData.serialNo = e[0].value
 | 
			
		||||
        this.formData.serialName = e[0].label
 | 
			
		||||
      }
 | 
			
		||||
      if(this.showMessageLevel) {
 | 
			
		||||
        this.formData.messageLevel = e[0].value
 | 
			
		||||
        this.formData.messageLevelName = e[0].label
 | 
			
		||||
      }
 | 
			
		||||
      if(this.showCyclingType) {
 | 
			
		||||
        this.formData.cyclingType = e[0].value
 | 
			
		||||
        this.formData.cyclingTypeName = e[0].label
 | 
			
		||||
      }
 | 
			
		||||
      if(this.showDate) {
 | 
			
		||||
        this.formData.startDate = e.year + '-' + e.month + '-' + e.day
 | 
			
		||||
      }
 | 
			
		||||
      if(this.showSatrt) {
 | 
			
		||||
        var startTime = e.hour + ':' + e.minute + ':' + e.second
 | 
			
		||||
        var myDate = new Date();
 | 
			
		||||
        var time = myDate.getHours() + ':' +  myDate.getMinutes() + ':' + myDate.getSeconds()
 | 
			
		||||
        if (this.timeToSec(startTime) - this.timeToSec(time) > 0) {
 | 
			
		||||
          this.formData.startTime = startTime
 | 
			
		||||
        }else {
 | 
			
		||||
          this.$u.toast('开始时间要大于当前时间')
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      if(this.showEnd) {
 | 
			
		||||
        var endTime = e.hour + ':' + e.minute + ':' + e.second
 | 
			
		||||
        console.log(this.timeToSec(endTime), this.timeToSec(this.formData.startTime))
 | 
			
		||||
        if (this.timeToSec(endTime) - this.timeToSec(this.formData.startTime) > 0) {
 | 
			
		||||
          this.formData.endTime = endTime
 | 
			
		||||
        } else {
 | 
			
		||||
          this.$u.toast('结束时间要大于开始时间')
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      this.init()
 | 
			
		||||
    },
 | 
			
		||||
    init() {
 | 
			
		||||
      this.showMedia = false
 | 
			
		||||
      this.showEquipment = false
 | 
			
		||||
      this.showMessageLevel = false
 | 
			
		||||
      this.showCyclingType = false
 | 
			
		||||
      this.showDate = false
 | 
			
		||||
      this.showSatrt = false
 | 
			
		||||
      this.showEnd = false
 | 
			
		||||
    },
 | 
			
		||||
    selectClick(showType, list) {
 | 
			
		||||
      this.showSelect = true
 | 
			
		||||
      this[showType] = true
 | 
			
		||||
      this.selectList = list
 | 
			
		||||
    },
 | 
			
		||||
    getMediaList() {
 | 
			
		||||
      this.$http.post(`/app/appdlbresource/list?current=1&size=10000`).then((res) => {
 | 
			
		||||
        if (res.code == 0) {
 | 
			
		||||
          this.mediaList = []
 | 
			
		||||
          if(res.data && res.data.records.length) {
 | 
			
		||||
            res.data.records.map((item) => {
 | 
			
		||||
              let info = {
 | 
			
		||||
                dictName: item.name,
 | 
			
		||||
                dictValue: item.id
 | 
			
		||||
              }
 | 
			
		||||
              this.mediaList.push(info)
 | 
			
		||||
            })
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
    getEquipmentList() {
 | 
			
		||||
      this.$http.post(`/app/appdlbquipment/getDlbDeviceList?current=1&size=10000&devStatus=5&keyword=`).then((res) => {
 | 
			
		||||
        if (res.code == 0) {
 | 
			
		||||
          this.equipmentList = []
 | 
			
		||||
          if(res.data && res.data.records.length) {
 | 
			
		||||
            res.data.records.map((item) => {
 | 
			
		||||
              let info = {
 | 
			
		||||
                dictName: item.deviceName,
 | 
			
		||||
                dictValue: item.serialNo
 | 
			
		||||
              }
 | 
			
		||||
              this.equipmentList.push(info)
 | 
			
		||||
            })
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
    checkClick(index) {
 | 
			
		||||
      this.dayList[index].isCheck = !this.dayList[index].isCheck
 | 
			
		||||
    },
 | 
			
		||||
    timeClick(showYear, showType) {
 | 
			
		||||
      this[showType] = true
 | 
			
		||||
      this.showDateTime = true
 | 
			
		||||
      if(showYear) {
 | 
			
		||||
        this.params = {
 | 
			
		||||
          year: true,
 | 
			
		||||
          month: true,
 | 
			
		||||
          day: true,
 | 
			
		||||
          hour: false,
 | 
			
		||||
          minute: false,
 | 
			
		||||
          second: false
 | 
			
		||||
        }
 | 
			
		||||
      }else {
 | 
			
		||||
        this.params = {
 | 
			
		||||
          year: false,
 | 
			
		||||
          month: false,
 | 
			
		||||
          day: false,
 | 
			
		||||
          hour: true,
 | 
			
		||||
          minute: true,
 | 
			
		||||
          second: true
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    timeToSec(time) {
 | 
			
		||||
      var s = "";
 | 
			
		||||
      var hour = time.split(":")[0];
 | 
			
		||||
      var min = time.split(":")[1];
 | 
			
		||||
      var second =  time.split(":")[2];
 | 
			
		||||
      s = Number(hour * 3600) + Number(min * 60) + Number(second)
 | 
			
		||||
      return s;
 | 
			
		||||
    }, 
 | 
			
		||||
  },
 | 
			
		||||
  created() {
 | 
			
		||||
    this.$dict.load('dlbMessageUrgency', 'dlbBroadTaskType', 'dlbDyclingType').then(() => {
 | 
			
		||||
      this.getMediaList()
 | 
			
		||||
      this.getEquipmentList()
 | 
			
		||||
      this.messageLevelList = this.$dict.getDict('dlbMessageUrgency')
 | 
			
		||||
      this.cyclingTypeList = this.$dict.getDict('dlbDyclingType')
 | 
			
		||||
    })
 | 
			
		||||
  },
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
.addPlay {
 | 
			
		||||
  padding-bottom: 128px;
 | 
			
		||||
  .content{
 | 
			
		||||
    padding-left: 32px;
 | 
			
		||||
    background-color: #fff;
 | 
			
		||||
    .item{
 | 
			
		||||
      width: 100%;
 | 
			
		||||
      padding: 34px 0;
 | 
			
		||||
      font-size: 32px;
 | 
			
		||||
      font-family: PingFangSC-Regular, PingFang SC;
 | 
			
		||||
      font-weight: 400;
 | 
			
		||||
      line-height: 44px;
 | 
			
		||||
      border-bottom: 1px solid #ddd;
 | 
			
		||||
      display: flex;
 | 
			
		||||
      color: #333;
 | 
			
		||||
      justify-content: space-between;
 | 
			
		||||
      .label{
 | 
			
		||||
        width: 198px;
 | 
			
		||||
        font-size: 32px;
 | 
			
		||||
      }
 | 
			
		||||
      .value{
 | 
			
		||||
        display: flex;
 | 
			
		||||
        align-items: center;
 | 
			
		||||
        justify-content: flex-end;
 | 
			
		||||
        font-size: 28px;
 | 
			
		||||
        flex: 1;
 | 
			
		||||
        padding-right: 32px;
 | 
			
		||||
        max-width: calc(100% - 198px);
 | 
			
		||||
        box-sizing: border-box;
 | 
			
		||||
        text-align: right;
 | 
			
		||||
 | 
			
		||||
        span {
 | 
			
		||||
          overflow: hidden;
 | 
			
		||||
          text-overflow: ellipsis;
 | 
			
		||||
          white-space: nowrap;
 | 
			
		||||
        }
 | 
			
		||||
        img{
 | 
			
		||||
          width: 32px;
 | 
			
		||||
          height: 32px;
 | 
			
		||||
          vertical-align: middle;
 | 
			
		||||
          margin-left: 6px;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      .color-999{
 | 
			
		||||
        color: #999;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  .radio-content{
 | 
			
		||||
    padding: 34px 32px 38px;
 | 
			
		||||
    border-bottom: 1px solid #ddd;
 | 
			
		||||
    background-color: #fff;
 | 
			
		||||
    .title{
 | 
			
		||||
      font-size: 32px;
 | 
			
		||||
      font-family: PingFangSC-Regular, PingFang SC;
 | 
			
		||||
      font-weight: 400;
 | 
			
		||||
      color: #333;
 | 
			
		||||
      line-height: 44px;
 | 
			
		||||
      margin-bottom: 54px;
 | 
			
		||||
      span{
 | 
			
		||||
        font-size: 24px;
 | 
			
		||||
        font-weight: 400;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    .item{
 | 
			
		||||
      display: inline-block;
 | 
			
		||||
      width: 320px;
 | 
			
		||||
      height: 112px;
 | 
			
		||||
      line-height: 112px;
 | 
			
		||||
      text-align: center;
 | 
			
		||||
      background: #F5F5F5;
 | 
			
		||||
      border-radius: 4px;
 | 
			
		||||
      font-size: 30px;
 | 
			
		||||
      font-family: PingFangSC-Medium, PingFang SC;
 | 
			
		||||
      font-weight: 500;
 | 
			
		||||
      color: #333;
 | 
			
		||||
      img{
 | 
			
		||||
        display: none;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    .active{
 | 
			
		||||
      background: #E7F1FE;
 | 
			
		||||
      color: #1174FE;
 | 
			
		||||
      position: relative;
 | 
			
		||||
      img{
 | 
			
		||||
        display: inline-block;
 | 
			
		||||
        position: absolute;
 | 
			
		||||
        bottom: 0;
 | 
			
		||||
        right: 0;
 | 
			
		||||
        width: 46px;
 | 
			
		||||
        height: 46px;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    .mar-r50 {
 | 
			
		||||
      margin-right: 50px;
 | 
			
		||||
    }
 | 
			
		||||
    .mini-item{
 | 
			
		||||
      display: inline-block;
 | 
			
		||||
      width: 128px;
 | 
			
		||||
      height: 72px;
 | 
			
		||||
      line-height: 72px;
 | 
			
		||||
      text-align: center;
 | 
			
		||||
      background: #F9F9F9;
 | 
			
		||||
      border-radius: 16px;
 | 
			
		||||
      color: #333;
 | 
			
		||||
      font-size: 28px;
 | 
			
		||||
      margin-right: 58px;
 | 
			
		||||
      margin-bottom: 32px;
 | 
			
		||||
    }
 | 
			
		||||
    .mini-item:nth-of-type(5) {
 | 
			
		||||
      margin-right: 0;
 | 
			
		||||
    }
 | 
			
		||||
    .mini-active{
 | 
			
		||||
      background: #F2F8FE;
 | 
			
		||||
      border: 1px solid #89B2EE;
 | 
			
		||||
      box-sizing: border-box;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  .btn{
 | 
			
		||||
    position: fixed;
 | 
			
		||||
    bottom: 0;
 | 
			
		||||
    left: 0;
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    height: 112px;
 | 
			
		||||
    line-height: 112px;
 | 
			
		||||
    text-align: center;
 | 
			
		||||
    background: #3975C6;
 | 
			
		||||
    font-size: 32px;
 | 
			
		||||
    font-family: PingFangSC-Medium, PingFang SC;
 | 
			
		||||
    font-weight: 500;
 | 
			
		||||
    color: #FFFFFF;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										167
									
								
								src/pages/bigHorn/bigHorn.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,167 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="bigHorn">
 | 
			
		||||
    <div class="header">
 | 
			
		||||
      <img src="./img/bigHorn-bg.png" alt="">
 | 
			
		||||
      <div class="content">
 | 
			
		||||
        <div class="item" @click="linkTo('./onlineList')">
 | 
			
		||||
          <img src="./img/bigHorn-icon1@2x.png" alt="">
 | 
			
		||||
          <div>在线设备</div>
 | 
			
		||||
          <!-- <h2>1</h2> -->
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="item" @click="linkTo('./playList')">
 | 
			
		||||
          <img src="./img/bigHorn-icon2@2x.png" alt="">
 | 
			
		||||
          <div>播放记录</div>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="item" @click="linkTo('./onlinePlayList')">
 | 
			
		||||
          <img src="./img/bigHorn-icon3@2x.png" alt="">
 | 
			
		||||
          <div>在播设备</div>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="banner">
 | 
			
		||||
      <div class="item" :class="item.bgClass" v-for="(item, index) in bannerList" :key="index" @click="linkTo(item.path)">
 | 
			
		||||
        <h2>{{item.title}}</h2>
 | 
			
		||||
        <div>{{item.text}}</div>
 | 
			
		||||
        <img :src="item.imgUrl" alt="">
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
<script> 
 | 
			
		||||
export default {
 | 
			
		||||
  name: "bigHorn",
 | 
			
		||||
  data() {
 | 
			
		||||
    return {
 | 
			
		||||
      bannerList: [
 | 
			
		||||
        {
 | 
			
		||||
          title: '素材播放',
 | 
			
		||||
          text: '支持音频立即播发和定时播发',
 | 
			
		||||
          imgUrl: require('./img/bigHorn-icon11@2x.png'),
 | 
			
		||||
          path: '/pages/bigHorn/addPlay',
 | 
			
		||||
          bgClass: 'bg-67A3F4'
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          title: '实时喊话',
 | 
			
		||||
          text: '实时在线喊话,远程广播通知',
 | 
			
		||||
          imgUrl: require('./img/bigHorn-icon22@2x.png'),
 | 
			
		||||
          bgClass: 'bg-4ED5BB'
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          title: '音频录制',
 | 
			
		||||
          text: '音频文件的录制',
 | 
			
		||||
          path: '/pages/resourcesManage/addPlay?type=1',
 | 
			
		||||
          imgUrl: require('./img/bigHorn-icon33@2x.png'),
 | 
			
		||||
          bgClass: 'bg-E5B565'
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          title: '媒资管理',
 | 
			
		||||
          path: '/pages/resourcesManage/resourcesManage',
 | 
			
		||||
          text: '支持音频文件和录音内容添加',
 | 
			
		||||
          imgUrl: require('./img/bigHorn-icon44@2x.png'),
 | 
			
		||||
          bgClass: 'bg-F19661'
 | 
			
		||||
        }
 | 
			
		||||
      ]
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    linkTo(url) {
 | 
			
		||||
      uni.navigateTo({url})
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  mounted() {
 | 
			
		||||
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
.bigHorn {
 | 
			
		||||
  .header{
 | 
			
		||||
    position: relative;
 | 
			
		||||
    img{
 | 
			
		||||
      width: 100%;
 | 
			
		||||
      height: 306px;
 | 
			
		||||
    }
 | 
			
		||||
    .content{
 | 
			
		||||
      width: 686px;
 | 
			
		||||
      padding: 40px 0;
 | 
			
		||||
      background: #FFFFFF;
 | 
			
		||||
      box-shadow: 0px 4px 8px 4px rgba(0, 0, 0, 0.06);
 | 
			
		||||
      border-radius: 12px;
 | 
			
		||||
      position: absolute;
 | 
			
		||||
      top: 210px;
 | 
			
		||||
      left: 50%;
 | 
			
		||||
      transform: translateX(-50%);
 | 
			
		||||
      display: flex;
 | 
			
		||||
      .item{
 | 
			
		||||
        text-align: center;
 | 
			
		||||
        flex: 1;
 | 
			
		||||
        img{
 | 
			
		||||
          width: 64px;
 | 
			
		||||
          height: 64px;
 | 
			
		||||
          margin-bottom: 18px;
 | 
			
		||||
        }
 | 
			
		||||
        div{
 | 
			
		||||
          font-size: 30px;
 | 
			
		||||
          font-family: PingFang-SC-Medium, PingFang-SC;
 | 
			
		||||
          font-weight: 500;
 | 
			
		||||
          color: #333;
 | 
			
		||||
          line-height: 42px;
 | 
			
		||||
          margin-bottom: 10px;
 | 
			
		||||
        }
 | 
			
		||||
        h2{
 | 
			
		||||
          font-size: 40px;
 | 
			
		||||
          font-family: DINAlternate-Bold, DINAlternate;
 | 
			
		||||
          font-weight: bold;
 | 
			
		||||
          color: #333;
 | 
			
		||||
          line-height: 48px;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  .banner{
 | 
			
		||||
    margin-top: 150px;
 | 
			
		||||
    .item{
 | 
			
		||||
      width: 686px;
 | 
			
		||||
      height: 190px;
 | 
			
		||||
      border-radius: 12px;
 | 
			
		||||
      margin: 0 auto 24px auto;
 | 
			
		||||
      padding: 40px 46px 0 80px;
 | 
			
		||||
      box-sizing: border-box;
 | 
			
		||||
      color: #FFF;
 | 
			
		||||
      position: relative;
 | 
			
		||||
      h2{
 | 
			
		||||
        font-size: 42px;
 | 
			
		||||
        font-family: PingFangSC-Medium, PingFang SC;
 | 
			
		||||
        font-weight: 500;
 | 
			
		||||
        line-height: 60px;
 | 
			
		||||
        margin-bottom: 16px;
 | 
			
		||||
      }
 | 
			
		||||
      div{
 | 
			
		||||
        font-size: 26px;
 | 
			
		||||
        font-family: PingFangSC-Regular, PingFang SC;
 | 
			
		||||
        font-weight: 400;
 | 
			
		||||
        color: #FFF;
 | 
			
		||||
        line-height: 32px;
 | 
			
		||||
      }
 | 
			
		||||
      img{
 | 
			
		||||
        width: 160px;
 | 
			
		||||
        position: absolute;
 | 
			
		||||
        top: 10px;
 | 
			
		||||
        right: 30px;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    .bg-67A3F4{
 | 
			
		||||
      background: #67A3F4;
 | 
			
		||||
    }
 | 
			
		||||
    .bg-4ED5BB{
 | 
			
		||||
      background: #4ED5BB;
 | 
			
		||||
    }
 | 
			
		||||
    .bg-E5B565{
 | 
			
		||||
      background: #E5B565;
 | 
			
		||||
    }
 | 
			
		||||
    .bg-F19661{
 | 
			
		||||
      background: #F19661;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								src/pages/bigHorn/img/bigHorn-bg.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 64 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								src/pages/bigHorn/img/bigHorn-icon11@2x.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 6.1 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								src/pages/bigHorn/img/bigHorn-icon1@2x.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 2.4 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								src/pages/bigHorn/img/bigHorn-icon22@2x.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 3.9 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								src/pages/bigHorn/img/bigHorn-icon2@2x.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 2.1 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								src/pages/bigHorn/img/bigHorn-icon33@2x.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 6.1 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								src/pages/bigHorn/img/bigHorn-icon3@2x.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 1.5 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								src/pages/bigHorn/img/bigHorn-icon44@2x.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 3.5 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								src/pages/bigHorn/img/bigHorn-lb@2x.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 2.1 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								src/pages/bigHorn/img/bigHorn-xz.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 1.3 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								src/pages/bigHorn/img/cir.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 795 B  | 
							
								
								
									
										
											BIN
										
									
								
								src/pages/bigHorn/img/lb@2x.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 2.1 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								src/pages/bigHorn/img/right-icon.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 269 B  | 
							
								
								
									
										
											BIN
										
									
								
								src/pages/bigHorn/img/search-icon.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 766 B  | 
							
								
								
									
										
											BIN
										
									
								
								src/pages/bigHorn/img/select-blue.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 1.1 KiB  | 
							
								
								
									
										93
									
								
								src/pages/bigHorn/onlineList.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,93 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="onlineList">
 | 
			
		||||
    <div class="record">
 | 
			
		||||
      <div class="item"  v-for="(item, index) in list" :key="index">
 | 
			
		||||
        <img src="./img/bigHorn-lb@2x.png" alt="">
 | 
			
		||||
        <div class="info">
 | 
			
		||||
          <p>{{item.deviceName}}</p>
 | 
			
		||||
          <span>{{item.areaName}}</span>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <ai-empty v-if="!list.length"></ai-empty>
 | 
			
		||||
    <AiBack></AiBack>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
<script> 
 | 
			
		||||
import AiEmpty from '@/components/AiEmpty/AiEmpty'
 | 
			
		||||
import AiBack from "@/components/AiBack";
 | 
			
		||||
export default {
 | 
			
		||||
  name: "onlineList",
 | 
			
		||||
  data() {
 | 
			
		||||
    return {
 | 
			
		||||
      page: {current: 1, size: 10, total: 0},
 | 
			
		||||
      list: []
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  components: {
 | 
			
		||||
    AiEmpty,
 | 
			
		||||
    AiBack
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    getList() {
 | 
			
		||||
      this.$http.post("/app/appdlbquipment/getDlbDeviceList", null, {
 | 
			
		||||
        params: {...this.page, devStatus: 5}
 | 
			
		||||
      }).then(res => {
 | 
			
		||||
        if (res?.data) {
 | 
			
		||||
          if (this.page.current > 1) {
 | 
			
		||||
            this.list = [...this.list, ...res.data.records]
 | 
			
		||||
          } else this.list = res.data.records
 | 
			
		||||
          this.page.total = res.data.total
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
    reachBottom() {
 | 
			
		||||
      if (this.page.total > this.list.length) {
 | 
			
		||||
        this.page.current++
 | 
			
		||||
        this.getList()
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  created() {
 | 
			
		||||
    this.getList()
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
.onlineList {
 | 
			
		||||
  .record{
 | 
			
		||||
    padding-left: 32px;
 | 
			
		||||
    background-color: #fff;
 | 
			
		||||
    .item{
 | 
			
		||||
      width: 100%;
 | 
			
		||||
      border-bottom: 1px solid #ddd;
 | 
			
		||||
      display: flex;
 | 
			
		||||
      padding: 12px 40px 16px 0;
 | 
			
		||||
      img{
 | 
			
		||||
        width: 48px;
 | 
			
		||||
        height: 48px;
 | 
			
		||||
        margin: 12px 16px 0 0;
 | 
			
		||||
      }
 | 
			
		||||
      .info{
 | 
			
		||||
        width: calc(100% - 100px);
 | 
			
		||||
        p{
 | 
			
		||||
          font-size: 34px;
 | 
			
		||||
          font-family: PingFang-SC-Medium, PingFang-SC;
 | 
			
		||||
          font-weight: 500;
 | 
			
		||||
          color: #333;
 | 
			
		||||
          line-height: 48px;
 | 
			
		||||
          margin-bottom: 12px;
 | 
			
		||||
        }
 | 
			
		||||
        span{
 | 
			
		||||
          font-size: 22px;
 | 
			
		||||
          font-family: PingFang-SC-Medium, PingFang-SC;
 | 
			
		||||
          font-weight: 500;
 | 
			
		||||
          color: #999;
 | 
			
		||||
          line-height: 32px;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										95
									
								
								src/pages/bigHorn/onlinePlayList.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,95 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="onlinePlayList">
 | 
			
		||||
    <div class="record">
 | 
			
		||||
      <div class="item" v-for="(item, index) in list" :key="index">
 | 
			
		||||
        <img src="./img/bigHorn-lb@2x.png" alt="">
 | 
			
		||||
        <div class="info">
 | 
			
		||||
          <p>{{item.deviceName}}</p>
 | 
			
		||||
          <span>{{item.createTime}}</span><br />
 | 
			
		||||
          <span>{{item.name}}</span>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <ai-empty v-if="!list.length"></ai-empty>
 | 
			
		||||
    <AiBack></AiBack>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
<script> 
 | 
			
		||||
import AiEmpty from '@/components/AiEmpty/AiEmpty'
 | 
			
		||||
import AiBack from "@/components/AiBack";
 | 
			
		||||
export default {
 | 
			
		||||
  name: "onlinePlayList",
 | 
			
		||||
  data() {
 | 
			
		||||
    return {
 | 
			
		||||
      page: {current: 1, size: 10, total: 0},
 | 
			
		||||
      list: []
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  components: {
 | 
			
		||||
    AiEmpty,
 | 
			
		||||
    AiBack
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  methods: {
 | 
			
		||||
    getList() {
 | 
			
		||||
      this.$http.post("/app/appdlbquipment/getDlbDeviceList", null, {
 | 
			
		||||
        params: {...this.page, devStatus: 1}
 | 
			
		||||
      }).then(res => {
 | 
			
		||||
        if (res?.data) {
 | 
			
		||||
          if (this.page.current > 1) {
 | 
			
		||||
            this.list = [...this.list, ...res.data.records]
 | 
			
		||||
          } else this.list = res.data.records
 | 
			
		||||
          this.page.total = res.data.total
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
    reachBottom() {
 | 
			
		||||
      if (this.page.total > this.list.length) {
 | 
			
		||||
        this.page.current++
 | 
			
		||||
        this.getList()
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  created() {
 | 
			
		||||
    this.getList()
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
.onlinePlayList {
 | 
			
		||||
  .record{
 | 
			
		||||
    padding-left: 32px;
 | 
			
		||||
    background-color: #fff;
 | 
			
		||||
    .item{
 | 
			
		||||
      width: 100%;
 | 
			
		||||
      border-bottom: 1px solid #ddd;
 | 
			
		||||
      display: flex;
 | 
			
		||||
      padding: 12px 40px 16px 0;
 | 
			
		||||
      img{
 | 
			
		||||
        width: 48px;
 | 
			
		||||
        height: 48px;
 | 
			
		||||
        margin: 12px 16px 0 0;
 | 
			
		||||
      }
 | 
			
		||||
      .info{
 | 
			
		||||
        width: calc(100% - 100px);
 | 
			
		||||
        p{
 | 
			
		||||
          font-size: 34px;
 | 
			
		||||
          font-family: PingFang-SC-Medium, PingFang-SC;
 | 
			
		||||
          font-weight: 500;
 | 
			
		||||
          color: #333;
 | 
			
		||||
          line-height: 48px;
 | 
			
		||||
          margin-bottom: 12px;
 | 
			
		||||
        }
 | 
			
		||||
        span{
 | 
			
		||||
          font-size: 22px;
 | 
			
		||||
          font-family: PingFang-SC-Medium, PingFang-SC;
 | 
			
		||||
          font-weight: 500;
 | 
			
		||||
          color: #999;
 | 
			
		||||
          line-height: 32px;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										138
									
								
								src/pages/bigHorn/playList.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,138 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="playList">
 | 
			
		||||
    <div class="title">
 | 
			
		||||
      <span>播放记录</span>
 | 
			
		||||
      <span>操作</span>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="record">
 | 
			
		||||
      <div class="item" v-for="(item, index) in list" :key="index"> 
 | 
			
		||||
        <div class="info">
 | 
			
		||||
          <p>{{item.messageName}}</p>
 | 
			
		||||
          <span>{{item.createTime}}</span><br />
 | 
			
		||||
          <span>{{item.deviceName}}</span>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="btn bg-3975C6" v-if="item.broadcastStatus == 0 || item.broadcastStatus == 1 || item.broadcastStatus == 2" @click="cancel(item.broadcastId)">撤销</div>
 | 
			
		||||
        <div class="btn bg-AFD0FC" v-if="item.broadcastStatus == 6">已取消</div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <AiBack></AiBack>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
<script> 
 | 
			
		||||
  import AiBack from "@/components/AiBack";
 | 
			
		||||
export default {
 | 
			
		||||
  name: "playList",
 | 
			
		||||
  data() {
 | 
			
		||||
    return {
 | 
			
		||||
      page: {current: 1, size: 10, total: 0},
 | 
			
		||||
      list: []
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  components: {
 | 
			
		||||
    AiBack
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    getList() {
 | 
			
		||||
      this.$http.post("/app/appzyvideobroadcast/getBroadcastRecords", null, {
 | 
			
		||||
        params: {...this.page}
 | 
			
		||||
      }).then(res => {
 | 
			
		||||
        if (res?.data) {
 | 
			
		||||
          if (this.page.current > 1) {
 | 
			
		||||
            this.list = [...this.list, ...res.data.records]
 | 
			
		||||
          } else this.list = res.data.records
 | 
			
		||||
          this.page.total = res.data.total
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
    reachBottom() {
 | 
			
		||||
      if (this.page.total > this.list.length) {
 | 
			
		||||
        this.page.current++
 | 
			
		||||
        this.getList()
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    cancel(id) {
 | 
			
		||||
      this.$confirm('确定撤回该广播?').then(() => {
 | 
			
		||||
        this.$http.post(`/app/appzyvideobroadcast/getBroadcastRecall?broadcastId=${id}`).then((res) => {
 | 
			
		||||
          if (res.code == 0) {
 | 
			
		||||
            this.$u.toast('撤回成功!')
 | 
			
		||||
            this.getList()
 | 
			
		||||
          }
 | 
			
		||||
        })
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  created() {
 | 
			
		||||
    this.$dict.load('dlbBroadcastStatus').then(() => {
 | 
			
		||||
      this.getList()
 | 
			
		||||
    })
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
.playList {
 | 
			
		||||
  .title{
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    height: 88px;
 | 
			
		||||
    line-height: 88px;
 | 
			
		||||
    background: #FFF;
 | 
			
		||||
    padding: 0 80px;
 | 
			
		||||
    display: flex;
 | 
			
		||||
    justify-content: space-between;
 | 
			
		||||
    color: #333;
 | 
			
		||||
    font-size: 34px;
 | 
			
		||||
    box-sizing: border-box;
 | 
			
		||||
    border-bottom: 1px solid #ddd;
 | 
			
		||||
  }
 | 
			
		||||
  .record{
 | 
			
		||||
    padding-left: 32px;
 | 
			
		||||
    background-color: #fff;
 | 
			
		||||
    .item{
 | 
			
		||||
      width: 100%;
 | 
			
		||||
      border-bottom: 1px solid #ddd;
 | 
			
		||||
      display: flex;
 | 
			
		||||
      justify-content: space-between;
 | 
			
		||||
      padding: 12px 40px 16px 0;
 | 
			
		||||
      box-sizing: border-box;
 | 
			
		||||
      .info{
 | 
			
		||||
        width: 480px;
 | 
			
		||||
        margin-right: 40px;
 | 
			
		||||
        word-break: break-all;
 | 
			
		||||
        p{
 | 
			
		||||
          font-size: 34px;
 | 
			
		||||
          font-family: PingFang-SC-Medium, PingFang-SC;
 | 
			
		||||
          font-weight: 500;
 | 
			
		||||
          color: #333;
 | 
			
		||||
          line-height: 48px;
 | 
			
		||||
          margin-bottom: 12px;
 | 
			
		||||
        }
 | 
			
		||||
        span{
 | 
			
		||||
          font-size: 22px;
 | 
			
		||||
          font-family: PingFang-SC-Medium, PingFang-SC;
 | 
			
		||||
          font-weight: 500;
 | 
			
		||||
          color: #999;
 | 
			
		||||
          line-height: 32px;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      .btn{
 | 
			
		||||
        width: 154px;
 | 
			
		||||
        height: 60px;
 | 
			
		||||
        border-radius: 8px;
 | 
			
		||||
        text-align: center;
 | 
			
		||||
        line-height: 60px;
 | 
			
		||||
        font-size: 30px;
 | 
			
		||||
        font-family: PingFang-SC-Medium, PingFang-SC;
 | 
			
		||||
        font-weight: 500;
 | 
			
		||||
        color: #FFF;
 | 
			
		||||
        margin-top: 18px;
 | 
			
		||||
      }
 | 
			
		||||
      .bg-3975C6{
 | 
			
		||||
        background: #3975C6;
 | 
			
		||||
      }
 | 
			
		||||
      .bg-AFD0FC{
 | 
			
		||||
        background: #AFD0FC;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										160
									
								
								src/pages/bigHorn/selectEquipment.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,160 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="selectEquipment">
 | 
			
		||||
    <div class="search">
 | 
			
		||||
      <div class="search-bg">
 | 
			
		||||
        <img src="./img/search-icon.png" alt="">
 | 
			
		||||
        <u-input v-model="value" type="text" placeholder="搜索设备名称" class="search-input" height="18" />
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="record">
 | 
			
		||||
      <div class="item">
 | 
			
		||||
        <img src="./img/cir.png" alt="" class="check-img">
 | 
			
		||||
        <img src="./img/lb@2x.png" alt="" class="voice-img">
 | 
			
		||||
        <div class="info">
 | 
			
		||||
          <div class="text">
 | 
			
		||||
            <p>村头大喇叭</p>
 | 
			
		||||
            <span>刘家河居委会</span>
 | 
			
		||||
          </div>
 | 
			
		||||
          <div class="status">在线</div>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="item">
 | 
			
		||||
        <img src="./img/cir.png" alt="" class="check-img">
 | 
			
		||||
        <img src="./img/lb@2x.png" alt="" class="voice-img">
 | 
			
		||||
        <div class="info">
 | 
			
		||||
          <div class="text">
 | 
			
		||||
            <p>村头大喇叭</p>
 | 
			
		||||
            <span>刘家河居委会</span>
 | 
			
		||||
          </div>
 | 
			
		||||
          <div class="status">在线</div>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="btn">
 | 
			
		||||
      <div>确定选择</div>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
<script> 
 | 
			
		||||
export default {
 | 
			
		||||
  name: "selectEquipment",
 | 
			
		||||
  data() {
 | 
			
		||||
    return {
 | 
			
		||||
      value: ''
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    
 | 
			
		||||
  },
 | 
			
		||||
  mounted() {
 | 
			
		||||
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
.selectEquipment {
 | 
			
		||||
  padding-bottom: 128px;
 | 
			
		||||
  .search{
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    height: 104px;
 | 
			
		||||
    background: #FFF;
 | 
			
		||||
    margin-bottom: 4px;
 | 
			
		||||
    padding: 20px 32px;
 | 
			
		||||
    box-sizing: border-box;
 | 
			
		||||
    .search-bg{
 | 
			
		||||
      width: 686px;
 | 
			
		||||
      height: 64px;
 | 
			
		||||
      padding: 14px 0;
 | 
			
		||||
      box-sizing: border-box;
 | 
			
		||||
      background: #F5F5F5;
 | 
			
		||||
      border-radius: 32px;
 | 
			
		||||
      position: relative;
 | 
			
		||||
      img{
 | 
			
		||||
        width: 32px;
 | 
			
		||||
        height: 32px;
 | 
			
		||||
        position: absolute;
 | 
			
		||||
        top: 16px;
 | 
			
		||||
        left: 32px;
 | 
			
		||||
      }
 | 
			
		||||
      .search-input{
 | 
			
		||||
        width: 590px;
 | 
			
		||||
        height: 36px;
 | 
			
		||||
        line-height: 36px;
 | 
			
		||||
        font-size: 28px;
 | 
			
		||||
        margin-left: 70px;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  .record{
 | 
			
		||||
    padding-left: 32px;
 | 
			
		||||
    background-color: #fff;
 | 
			
		||||
    .item{
 | 
			
		||||
      width: 100%;
 | 
			
		||||
      display: flex;
 | 
			
		||||
      border-bottom: 1px solid #ddd;
 | 
			
		||||
      .check-img{
 | 
			
		||||
        width: 32px;
 | 
			
		||||
        height: 32px;
 | 
			
		||||
        margin: 32px 32px 0 0;
 | 
			
		||||
      }
 | 
			
		||||
      .voice-img{
 | 
			
		||||
        width: 48px;
 | 
			
		||||
        height: 48px;
 | 
			
		||||
        margin: 28px 16px 0 0;
 | 
			
		||||
      }
 | 
			
		||||
      .info{
 | 
			
		||||
        width: calc(100% - 148px);
 | 
			
		||||
        padding: 18px 0;
 | 
			
		||||
        line-height: 44px;
 | 
			
		||||
        font-size: 34px;
 | 
			
		||||
        display: flex;
 | 
			
		||||
        justify-content: space-between;
 | 
			
		||||
        .text{
 | 
			
		||||
          p{
 | 
			
		||||
            font-family: PingFang-SC-Medium, PingFang-SC;
 | 
			
		||||
            font-weight: 500;
 | 
			
		||||
            color: #333;
 | 
			
		||||
            margin-bottom: 8px;
 | 
			
		||||
          }
 | 
			
		||||
          span{
 | 
			
		||||
            font-size: 26px;
 | 
			
		||||
            font-family: PingFang-SC-Medium, PingFang-SC;
 | 
			
		||||
            font-weight: 500;
 | 
			
		||||
            color: #999;
 | 
			
		||||
            line-height: 36px;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
        .status{
 | 
			
		||||
          font-size: 34px;
 | 
			
		||||
          font-family: PingFang-SC-Medium, PingFang-SC;
 | 
			
		||||
          font-weight: 500;
 | 
			
		||||
          color: #4E8EEE;
 | 
			
		||||
          line-height: 48px;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  .btn{
 | 
			
		||||
    position: fixed;
 | 
			
		||||
    bottom: 0;
 | 
			
		||||
    left: 0;
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    height: 128px;
 | 
			
		||||
    background: #FFF;
 | 
			
		||||
    border-top: 1px solid #ddd;
 | 
			
		||||
    padding: 24px 32px 24px 0;
 | 
			
		||||
    box-sizing: border-box;
 | 
			
		||||
    div{
 | 
			
		||||
      width: 192px;
 | 
			
		||||
      height: 80px;
 | 
			
		||||
      line-height: 80px;
 | 
			
		||||
      text-align: center;
 | 
			
		||||
      background: #3975C6;
 | 
			
		||||
      border-radius: 4px;
 | 
			
		||||
      color: #fff;
 | 
			
		||||
      font-size: 32px;
 | 
			
		||||
      float: right;
 | 
			
		||||
    } 
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										83
									
								
								src/pages/bigHorn/selectMp3.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,83 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="selectMp3">
 | 
			
		||||
    <div class="record">
 | 
			
		||||
      <div class="item">
 | 
			
		||||
        <img src="./img/cir.png" alt="">
 | 
			
		||||
        <div class="info">
 | 
			
		||||
          <p>村头大喇叭</p>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="btn">
 | 
			
		||||
      <div>确定选择</div>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
<script> 
 | 
			
		||||
export default {
 | 
			
		||||
  name: "selectMp3",
 | 
			
		||||
  data() {
 | 
			
		||||
    return {
 | 
			
		||||
      
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    
 | 
			
		||||
  },
 | 
			
		||||
  mounted() {
 | 
			
		||||
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
.selectMp3 {
 | 
			
		||||
  padding-bottom: 128px;
 | 
			
		||||
  .record{
 | 
			
		||||
    padding-left: 32px;
 | 
			
		||||
    background-color: #fff;
 | 
			
		||||
    .item{
 | 
			
		||||
      width: 100%;
 | 
			
		||||
      display: flex;
 | 
			
		||||
      img{
 | 
			
		||||
        width: 32px;
 | 
			
		||||
        height: 32px;
 | 
			
		||||
        margin: 40px 16px 0 0;
 | 
			
		||||
      }
 | 
			
		||||
      .info{
 | 
			
		||||
        width: calc(100% - 60px);
 | 
			
		||||
        padding-bottom: 16px;
 | 
			
		||||
        padding: 34px 0;
 | 
			
		||||
        line-height: 44px;
 | 
			
		||||
        border-bottom: 1px solid #ddd;
 | 
			
		||||
        font-size: 34px;
 | 
			
		||||
        font-family: PingFang-SC-Medium, PingFang-SC;
 | 
			
		||||
        font-weight: 500;
 | 
			
		||||
        color: #333;
 | 
			
		||||
        margin-left: 16px;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  .btn{
 | 
			
		||||
    position: fixed;
 | 
			
		||||
    bottom: 0;
 | 
			
		||||
    left: 0;
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    height: 128px;
 | 
			
		||||
    background: #FFF;
 | 
			
		||||
    border-top: 1px solid #ddd;
 | 
			
		||||
    padding: 24px 32px 24px 0;
 | 
			
		||||
    box-sizing: border-box;
 | 
			
		||||
    div{
 | 
			
		||||
      width: 192px;
 | 
			
		||||
      height: 80px;
 | 
			
		||||
      line-height: 80px;
 | 
			
		||||
      text-align: center;
 | 
			
		||||
      background: #3975C6;
 | 
			
		||||
      border-radius: 4px;
 | 
			
		||||
      color: #fff;
 | 
			
		||||
      font-size: 32px;
 | 
			
		||||
      float: right;
 | 
			
		||||
    } 
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										268
									
								
								src/pages/casuallyask/casuallyask.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,268 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="casuallyask">
 | 
			
		||||
    <div class="banner">
 | 
			
		||||
      <picker :range="dictList" @change="bindPickerChange" range-key="dictName">
 | 
			
		||||
        <div class="picker">
 | 
			
		||||
          {{ askType }}
 | 
			
		||||
          <u-icon
 | 
			
		||||
              name="arrow-down"
 | 
			
		||||
              :custom-style="{ margin: '0 5px' }"
 | 
			
		||||
          ></u-icon>
 | 
			
		||||
        </div>
 | 
			
		||||
      </picker>
 | 
			
		||||
      <u-search
 | 
			
		||||
          placeholder="请输入标题"
 | 
			
		||||
          :show-action="false"
 | 
			
		||||
          v-model="keyword"
 | 
			
		||||
          @search="onSearch"
 | 
			
		||||
      />
 | 
			
		||||
    </div>
 | 
			
		||||
    <u-tabs
 | 
			
		||||
        class="nav"
 | 
			
		||||
        :list="tabs"
 | 
			
		||||
        :is-scroll="false"
 | 
			
		||||
        :current="currentType"
 | 
			
		||||
        font-size="32"
 | 
			
		||||
        bar-width="192"
 | 
			
		||||
        height="96"
 | 
			
		||||
        @change="handleTabClick"
 | 
			
		||||
    ></u-tabs>
 | 
			
		||||
    <div class="body" v-if="eventList.length !== 0">
 | 
			
		||||
      <div
 | 
			
		||||
          class="content"
 | 
			
		||||
          v-for="(item, index) in eventList"
 | 
			
		||||
          :key="index"
 | 
			
		||||
          @click="detail(item)"
 | 
			
		||||
      >
 | 
			
		||||
        <u-row>
 | 
			
		||||
          <div>
 | 
			
		||||
            <div class="top">
 | 
			
		||||
 | 
			
		||||
              <text :class="item.type == '0' ? 'active' : 'noactive'">
 | 
			
		||||
                {{ $dict.getLabel('leaveMessageType', item.type) }}
 | 
			
		||||
              </text>
 | 
			
		||||
              <!-- 村 -->
 | 
			
		||||
              <text class="areaName" v-if="item.areaName">{{ item.areaName }}:</text>
 | 
			
		||||
              <!-- 问题 -->
 | 
			
		||||
              <text class="title">{{ item.title }}</text>
 | 
			
		||||
            </div>
 | 
			
		||||
 | 
			
		||||
            <div class="cont">
 | 
			
		||||
              <span class="name_time">留言人:</span>
 | 
			
		||||
              <text class="text_c"> {{ item.leaveName }}</text>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="cont">
 | 
			
		||||
              <text class="name_time">留言时间:</text>
 | 
			
		||||
              <text class="text_c"> {{ item.createTime }}</text>
 | 
			
		||||
            </div>
 | 
			
		||||
          </div>
 | 
			
		||||
        </u-row>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <AiEmpty v-else/>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import AiEmpty from '../../components/AiEmpty/AiEmpty'
 | 
			
		||||
import URow from '../../uview/components/u-row/u-row.vue'
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: 'casuallyAsk',
 | 
			
		||||
  // 组件
 | 
			
		||||
  components: {URow, AiEmpty},
 | 
			
		||||
  props: {},
 | 
			
		||||
  data() {
 | 
			
		||||
    return {
 | 
			
		||||
      page: {current: 1, size: 10, total: 0},
 | 
			
		||||
      dictList: [], // 字典
 | 
			
		||||
      index: 0, // 留言类型 0投诉 1咨询 2建议
 | 
			
		||||
      keyword: '',
 | 
			
		||||
      askType: '提问类型',
 | 
			
		||||
      askIndex: '',
 | 
			
		||||
      currentType: 0, // 默认value的值(0待我回复)(1已回复)(2处理完成)
 | 
			
		||||
      eventList: [] // 数据列表
 | 
			
		||||
      // temp: { '0': '投诉', '1': '建议', '2': '咨询' }
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  // 计算
 | 
			
		||||
  computed: {
 | 
			
		||||
    tabs() {
 | 
			
		||||
      return [
 | 
			
		||||
        {name: '待我回复', value: 0},
 | 
			
		||||
        {name: '我已回复', value: 1},
 | 
			
		||||
        {name: '处理完成', value: 2}
 | 
			
		||||
      ]
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  // 实例创建后
 | 
			
		||||
  onShow() {
 | 
			
		||||
    this.$dict.load('leaveMessageType').then(() => {
 | 
			
		||||
      this.dictList = this.$dict.getDict('leaveMessageType')
 | 
			
		||||
      this.getList()
 | 
			
		||||
    })
 | 
			
		||||
  },
 | 
			
		||||
  // 方法
 | 
			
		||||
  methods: {
 | 
			
		||||
    // 点击 value的值(0待我回复)(1已回复)(2处理完成)
 | 
			
		||||
    handleTabClick(i) {
 | 
			
		||||
      this.currentType = i
 | 
			
		||||
      this.getList()
 | 
			
		||||
    },
 | 
			
		||||
    getList() {
 | 
			
		||||
      this.$http.post(`/app/appleavemessage/list`, null, {
 | 
			
		||||
        params: {
 | 
			
		||||
          ...this.page,
 | 
			
		||||
          title: this.keyword,
 | 
			
		||||
          status: this.currentType,
 | 
			
		||||
          type: this.askIndex
 | 
			
		||||
        }
 | 
			
		||||
      }).then(res => {
 | 
			
		||||
        if (res?.data) {
 | 
			
		||||
          this.page.total = res.data.total
 | 
			
		||||
          if (this.page.current > 1)
 | 
			
		||||
            this.eventList = [...this.eventList, res.data.records]
 | 
			
		||||
          else this.eventList = res.data.records
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
    detail(item) {
 | 
			
		||||
      uni.navigateTo({
 | 
			
		||||
        url: `/pages/casuallyask/casuallyaskDetail?id=${item.id}&type=${item.type}`
 | 
			
		||||
        //  url: `/pages/casuallyask/casuallyaskDetail?id=${item.id}`
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
    // 提问类型
 | 
			
		||||
    bindPickerChange(e) {
 | 
			
		||||
      let index = e.detail.value
 | 
			
		||||
      this.askType = this.dictList[index].dictName
 | 
			
		||||
      this.askIndex = index
 | 
			
		||||
      this.getList()
 | 
			
		||||
    },
 | 
			
		||||
    onSearch(e) {
 | 
			
		||||
      this.keyword = e
 | 
			
		||||
      this.getList()
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  onReachBottom() {
 | 
			
		||||
    if (this.eventList.length < this.page.total) {
 | 
			
		||||
      this.page.current++
 | 
			
		||||
      this.getList()
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style scoped lang="scss">
 | 
			
		||||
.casuallyask {
 | 
			
		||||
  min-height: 100%;
 | 
			
		||||
  background: #f5f5f5;
 | 
			
		||||
  padding-top: 64px;
 | 
			
		||||
 | 
			
		||||
  .banner {
 | 
			
		||||
    position: fixed;
 | 
			
		||||
    top: 0;
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    background-color: #fff;
 | 
			
		||||
    height: 80px;
 | 
			
		||||
    line-height: 80px;
 | 
			
		||||
    display: flex;
 | 
			
		||||
    align-items: center;
 | 
			
		||||
    justify-content: space-between;
 | 
			
		||||
    box-sizing: border-box;
 | 
			
		||||
    padding: 0 30px 0 30px;
 | 
			
		||||
 | 
			
		||||
    .picker {
 | 
			
		||||
      font-size: 30px;
 | 
			
		||||
      font-weight: 500;
 | 
			
		||||
      color: #333333;
 | 
			
		||||
      margin-right: 8px;
 | 
			
		||||
 | 
			
		||||
      .u-icon-wrap {
 | 
			
		||||
        margin-left: 25px;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .nav {
 | 
			
		||||
    position: fixed;
 | 
			
		||||
    top: 80px;
 | 
			
		||||
    background-color: #ffffff;
 | 
			
		||||
    height: 96px;
 | 
			
		||||
    padding-top: 8px;
 | 
			
		||||
    width: 100%;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .body {
 | 
			
		||||
    padding: 114px 0 0 0;
 | 
			
		||||
 | 
			
		||||
    .content {
 | 
			
		||||
      background-color: #ffffff;
 | 
			
		||||
      box-sizing: border-box;
 | 
			
		||||
      padding: 34px 32px;
 | 
			
		||||
      margin: 32px 20px;
 | 
			
		||||
 | 
			
		||||
      .top {
 | 
			
		||||
        display: flex;
 | 
			
		||||
        align-items: center;
 | 
			
		||||
        width: 100%;
 | 
			
		||||
 | 
			
		||||
        .typeBox {
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .noactive {
 | 
			
		||||
          text-align: center;
 | 
			
		||||
          color: #2266ff;
 | 
			
		||||
          width: 70px;
 | 
			
		||||
          height: 44px;
 | 
			
		||||
          line-height: 44px;
 | 
			
		||||
          border-radius: 8px;
 | 
			
		||||
          background-color: #e8efff;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .active {
 | 
			
		||||
          text-align: center;
 | 
			
		||||
          color: #ff4466;
 | 
			
		||||
          line-height: 44px;
 | 
			
		||||
          width: 70px;
 | 
			
		||||
          height: 44px;
 | 
			
		||||
          border-radius: 8px;
 | 
			
		||||
          background-color: #ffebef;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .areaName {
 | 
			
		||||
          display: inline-block;
 | 
			
		||||
          color: #333;
 | 
			
		||||
          font-size: 32px;
 | 
			
		||||
          margin-left: 15px;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .title {
 | 
			
		||||
          color: #333;
 | 
			
		||||
          font-size: 32px;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .cont {
 | 
			
		||||
        margin: 10px 0;
 | 
			
		||||
 | 
			
		||||
        .name_time {
 | 
			
		||||
          display: inline-block;
 | 
			
		||||
          width: 150px;
 | 
			
		||||
          height: 24px;
 | 
			
		||||
          color: #999;
 | 
			
		||||
          font-size: 30px;
 | 
			
		||||
          // font-weight: 800;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .text_c {
 | 
			
		||||
          color: #343d65;
 | 
			
		||||
          font-size: 30px;
 | 
			
		||||
          // font-weight: 800;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										442
									
								
								src/pages/casuallyask/casuallyaskDetail.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,442 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="casuallyaskDetail">
 | 
			
		||||
    <div class="detail">
 | 
			
		||||
      <div class="headerTitle" flex>
 | 
			
		||||
        <div class="temp">
 | 
			
		||||
          [{{ $dict.getLabel('leaveMessageType', detail.type) }}]
 | 
			
		||||
        </div>
 | 
			
		||||
        <span class="areaName">{{ detail.areaName }}</span>
 | 
			
		||||
        <span>{{ detail.title }}</span>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="leaveName_leavePhone">
 | 
			
		||||
        <!-- 顶部圆形头像 -->
 | 
			
		||||
        <span class="icon">{{ detail.headPortrait || $formatName(detail.leaveName) }}</span>
 | 
			
		||||
        <span class="leaveName">{{ detail.leaveName }}</span>
 | 
			
		||||
        <span class="leavePhone" v-if="detail.leavePhone">({{ detail.leavePhone }})</span>
 | 
			
		||||
      </div>
 | 
			
		||||
      <!-- 编号 -->
 | 
			
		||||
      <div class="info-item">
 | 
			
		||||
        <span class="label">
 | 
			
		||||
          <u-icon name="order"></u-icon>
 | 
			
		||||
        </span>
 | 
			
		||||
        <span class="value">{{ detail.msgCode }}</span>
 | 
			
		||||
      </div>
 | 
			
		||||
      <!-- 日期 -->
 | 
			
		||||
      <div class="info-item">
 | 
			
		||||
        <span class="label">
 | 
			
		||||
          <u-icon name="clock"></u-icon>
 | 
			
		||||
        </span>
 | 
			
		||||
        <span class="value">{{ detail.createTime }}</span>
 | 
			
		||||
      </div>
 | 
			
		||||
      <!-- 进度-->
 | 
			
		||||
      <div class="info-item">
 | 
			
		||||
        <span class="label"><u-icon name="tags"/></span>
 | 
			
		||||
        <text class="status">{{
 | 
			
		||||
            $dict.getLabel('leaveMessageStatus', detail.status)
 | 
			
		||||
          }}
 | 
			
		||||
        </text>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="content_text_img">
 | 
			
		||||
        <!-- 提问内容 -->
 | 
			
		||||
        <div class="content_text">
 | 
			
		||||
          {{ detail.content }}
 | 
			
		||||
        </div>
 | 
			
		||||
        <!-- 提问内容的图片 -->
 | 
			
		||||
        <div class="imageList">
 | 
			
		||||
          <ai-image preview :src="items.url" alt="" v-for="(items, i) in imgList" :key="i"/>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="reply_content" v-if="detail.status == 1 || detail.status == 2">
 | 
			
		||||
        <div class="reply_title">
 | 
			
		||||
          <img src="https://cdn.cunwuyun.cn/img/dialogue.svg" alt=""/>
 | 
			
		||||
          <p>沟通记录</p>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="reply_list">
 | 
			
		||||
          <div class="item" v-for="(item, index) in appLeaveMessageReplyList" :key="index">
 | 
			
		||||
            <div class="item_top">
 | 
			
		||||
              <div class="item_left">
 | 
			
		||||
                <div class="icon">
 | 
			
		||||
                  {{ detail.headPortrait || $formatName(item.createUserName) }}
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="name fill">
 | 
			
		||||
                  <div class="createUserName_createUnitName">
 | 
			
		||||
                    <span v-if="item.createUserId == user.id" class="reply_font">我的回复</span>
 | 
			
		||||
                    <template v-else>
 | 
			
		||||
                      <span class="createUserName">{{ item.createUserName }} </span>
 | 
			
		||||
                      <span class="createUserName" v-if="item.createUserPhone">({{ item.createUserPhone }})</span>
 | 
			
		||||
                    </template>
 | 
			
		||||
                  </div>
 | 
			
		||||
                  <div flex v-if="item.createUserId != user.id">
 | 
			
		||||
                    <!-- 回复单位 -->
 | 
			
		||||
                    <span class="createUnitName">{{ item.createUnitName }}</span>
 | 
			
		||||
                    <span class="reply">回复</span>
 | 
			
		||||
                  </div>
 | 
			
		||||
                </div>
 | 
			
		||||
              </div>
 | 
			
		||||
              <div class="item_right">{{ item.createTime }}</div>
 | 
			
		||||
            </div>
 | 
			
		||||
            <!-- 回复内容 -->
 | 
			
		||||
            <div class="myreply_con">
 | 
			
		||||
              <div class="myreply_text">
 | 
			
		||||
                {{ item.content }}
 | 
			
		||||
              </div>
 | 
			
		||||
              <!-- 回复图片 -->
 | 
			
		||||
              <div class="imageList">
 | 
			
		||||
                <ai-image v-for="img in item.images" :key="img.id" preview :src="img.url"/>
 | 
			
		||||
              </div>
 | 
			
		||||
              <!--  -->
 | 
			
		||||
            </div>
 | 
			
		||||
          </div>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="close_reply" v-if="detail.status == 0 || detail.status == 1">
 | 
			
		||||
      <div class="btn" @click="close">关闭留言</div>
 | 
			
		||||
      <div class="btn reply" @click="reply">回复</div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <u-modal
 | 
			
		||||
        v-model="show"
 | 
			
		||||
        :content="content"
 | 
			
		||||
        cancel-color="#2979ff"
 | 
			
		||||
        title=""
 | 
			
		||||
        :async-close="true"
 | 
			
		||||
        :show-cancel-button="true"
 | 
			
		||||
        @confirm="handleCloseMessage"
 | 
			
		||||
        @cancel="show = false"/>
 | 
			
		||||
    <back/>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import back from '../../components/AiBack'
 | 
			
		||||
import {mapState} from 'vuex'
 | 
			
		||||
import AiImage from "../../components/AiImage";
 | 
			
		||||
import UImage from "../../uview/components/u-image/u-image";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: 'casuallyaskDetail',
 | 
			
		||||
  components: {UImage, AiImage, back},
 | 
			
		||||
  props: {},
 | 
			
		||||
  computed: {
 | 
			
		||||
    ...mapState(['user'])
 | 
			
		||||
  },
 | 
			
		||||
  onLoad(options) {
 | 
			
		||||
    this.getDetail(options.id)
 | 
			
		||||
  },
 | 
			
		||||
  onShow() {
 | 
			
		||||
    this.$dict.load('leaveMessageStatus', 'leaveMessageType')
 | 
			
		||||
  },
 | 
			
		||||
  data() {
 | 
			
		||||
    return {
 | 
			
		||||
      objdie: '', // id
 | 
			
		||||
      appLeaveMessageReplyList: [], //遍历得到的数据
 | 
			
		||||
      show: false, // 默认关闭模态框
 | 
			
		||||
      content: '关闭留言后,双方都无法再进行回复,是否确定关闭本次留言?',
 | 
			
		||||
      msgCode: null,
 | 
			
		||||
      imgList: [],
 | 
			
		||||
      detail: {}
 | 
			
		||||
      // images:[]
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    getDetail(id = this.detail.id) {
 | 
			
		||||
      this.$http.post(`/app/appleavemessage/queryDetailById?id=${id}`,).then(res => {
 | 
			
		||||
        if (res?.data) {
 | 
			
		||||
          this.detail = res.data
 | 
			
		||||
          this.imgList = JSON.parse(this.detail.images)
 | 
			
		||||
          this.appLeaveMessageReplyList = res.data.appLeaveMessageReplyList.map(item => ({
 | 
			
		||||
            ...item,
 | 
			
		||||
            images: JSON.parse(item.images).map(e => ({url: e.url || e?.file?.accessUrl, id: e.file?.id}))
 | 
			
		||||
          }))
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
    // 关闭留言
 | 
			
		||||
    close() {
 | 
			
		||||
      this.show = true
 | 
			
		||||
      this.getDetail()
 | 
			
		||||
    },
 | 
			
		||||
    // 确定关闭留言
 | 
			
		||||
    handleCloseMessage() {
 | 
			
		||||
      this.$http.post(`/app/appleavemessage/release?id=${this.objdie}&status=2`).then(res => {
 | 
			
		||||
        if (res?.code == 0) {
 | 
			
		||||
          this.getDetail()
 | 
			
		||||
          uni.navigateTo({url: `./closemsg?flag=true`})
 | 
			
		||||
        }
 | 
			
		||||
      }).catch(() => {
 | 
			
		||||
        uni.navigateTo({url: `./closemsg?flag=false`})
 | 
			
		||||
      })
 | 
			
		||||
      this.show = false
 | 
			
		||||
    },
 | 
			
		||||
    // 去回复
 | 
			
		||||
    reply() {
 | 
			
		||||
      uni.navigateTo({url: `./reply?msgCode=${this.detail.msgCode}`})
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
.casuallyaskDetail {
 | 
			
		||||
  padding-bottom: 80px;
 | 
			
		||||
 | 
			
		||||
  .detail {
 | 
			
		||||
    padding: 15px 32px 112px 32px;
 | 
			
		||||
    background-color: #fff;
 | 
			
		||||
    font-size: 30px;
 | 
			
		||||
    font-weight: 400;
 | 
			
		||||
    color: #343D65;
 | 
			
		||||
 | 
			
		||||
    .headerTitle {
 | 
			
		||||
      font-size: 40px;
 | 
			
		||||
      font-weight: bold;
 | 
			
		||||
      color: #333;
 | 
			
		||||
      line-height: 64px;
 | 
			
		||||
      letter-spacing: 2px;
 | 
			
		||||
      flex-wrap: wrap;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .leaveName_leavePhone {
 | 
			
		||||
      height: 56px;
 | 
			
		||||
      margin: 20px 0 36px 0;
 | 
			
		||||
 | 
			
		||||
      .icon {
 | 
			
		||||
        display: inline-block;
 | 
			
		||||
        width: 56px;
 | 
			
		||||
        height: 56px;
 | 
			
		||||
        line-height: 56px;
 | 
			
		||||
        border-radius: 50%;
 | 
			
		||||
        background-color: #2266ff;
 | 
			
		||||
        color: #fff;
 | 
			
		||||
        font-size: 22px;
 | 
			
		||||
        vertical-align: middle;
 | 
			
		||||
        text-align: center;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .leaveName {
 | 
			
		||||
        // display: block;
 | 
			
		||||
        margin-left: 20px;
 | 
			
		||||
        color: #343d65;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      // .leavePhone {
 | 
			
		||||
      // }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .info-item {
 | 
			
		||||
      height: 40px;
 | 
			
		||||
      line-height: 40px;
 | 
			
		||||
      font-size: 28px;
 | 
			
		||||
      margin-bottom: 8px;
 | 
			
		||||
 | 
			
		||||
      .label {
 | 
			
		||||
        display: inline-block;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .value {
 | 
			
		||||
        display: inline-block;
 | 
			
		||||
        margin-left: 20px;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .status {
 | 
			
		||||
        display: inline-block;
 | 
			
		||||
        margin-left: 20px;
 | 
			
		||||
        // color: #999;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .content_text_img {
 | 
			
		||||
      margin-top: 64px;
 | 
			
		||||
      max-height: 700px;
 | 
			
		||||
      color: #000;
 | 
			
		||||
      font-size: 32px;
 | 
			
		||||
      // font-weight: 800;
 | 
			
		||||
      overflow: hidden;
 | 
			
		||||
 | 
			
		||||
      .content_text {
 | 
			
		||||
        width: 100%;
 | 
			
		||||
        margin-bottom: 12px;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .reply_content {
 | 
			
		||||
      margin-top: 25px;
 | 
			
		||||
 | 
			
		||||
      .reply_title {
 | 
			
		||||
        margin-top: 25px;
 | 
			
		||||
        width: 225px;
 | 
			
		||||
        height: 45px;
 | 
			
		||||
        line-height: 45px;
 | 
			
		||||
 | 
			
		||||
        img {
 | 
			
		||||
          vertical-align: middle;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        p {
 | 
			
		||||
          display: inline-block;
 | 
			
		||||
          color: #333;
 | 
			
		||||
          // font-weight: 800;
 | 
			
		||||
          margin-left: 10px;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .reply_list {
 | 
			
		||||
        .item {
 | 
			
		||||
          .item_top {
 | 
			
		||||
            display: flex;
 | 
			
		||||
            justify-content: space-between;
 | 
			
		||||
            margin-top: 10px;
 | 
			
		||||
 | 
			
		||||
            .item_left {
 | 
			
		||||
              display: flex;
 | 
			
		||||
              align-items: center;
 | 
			
		||||
              flex: 1;
 | 
			
		||||
              min-width: 0;
 | 
			
		||||
 | 
			
		||||
              .icon {
 | 
			
		||||
                display: block;
 | 
			
		||||
                flex-shrink: 0;
 | 
			
		||||
                width: 64px;
 | 
			
		||||
                height: 64px;
 | 
			
		||||
                line-height: 64px;
 | 
			
		||||
                border-radius: 50%;
 | 
			
		||||
                background-color: #2266ff;
 | 
			
		||||
                color: #fff;
 | 
			
		||||
                font-size: 23px;
 | 
			
		||||
                text-align: center;
 | 
			
		||||
                margin-right: 10px;
 | 
			
		||||
              }
 | 
			
		||||
 | 
			
		||||
              .name {
 | 
			
		||||
                display: flex;
 | 
			
		||||
                flex-direction: column;
 | 
			
		||||
 | 
			
		||||
                .createUnitName {
 | 
			
		||||
                  color: #135ab8;
 | 
			
		||||
                  margin-right: 8px;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                .createUserName_createUnitName {
 | 
			
		||||
                  width: 100%;
 | 
			
		||||
                  display: flex;
 | 
			
		||||
 | 
			
		||||
                  .reply_font {
 | 
			
		||||
                    width: 120px;
 | 
			
		||||
                    color: #333333;
 | 
			
		||||
                    font-size: 28px;
 | 
			
		||||
                  }
 | 
			
		||||
 | 
			
		||||
                  .createUserName {
 | 
			
		||||
                    margin-bottom: 5px;
 | 
			
		||||
                    color: #135ab8;
 | 
			
		||||
                  }
 | 
			
		||||
                }
 | 
			
		||||
              }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            .item_right {
 | 
			
		||||
              font-size: 26px;
 | 
			
		||||
              color: #999;
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          .myreply_con {
 | 
			
		||||
            width: 570px;
 | 
			
		||||
            background-color: #f3f6f9;
 | 
			
		||||
            margin: 24px 0 0 80px;
 | 
			
		||||
            padding: 14px;
 | 
			
		||||
 | 
			
		||||
            .myreply_text {
 | 
			
		||||
              overflow: auto;
 | 
			
		||||
              word-wrap: break-word;
 | 
			
		||||
              word-break: break-all;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            .imageList {
 | 
			
		||||
              display: flex;
 | 
			
		||||
              flex-wrap: wrap;
 | 
			
		||||
 | 
			
		||||
              .AiImage {
 | 
			
		||||
                margin: 0 12px 12px 0;
 | 
			
		||||
              }
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .no_yes_reply {
 | 
			
		||||
          .con_title {
 | 
			
		||||
            display: flex;
 | 
			
		||||
            flex-direction: row;
 | 
			
		||||
            justify-content: space-between;
 | 
			
		||||
            margin-top: 16px;
 | 
			
		||||
            height: 64px;
 | 
			
		||||
            line-height: 64px;
 | 
			
		||||
 | 
			
		||||
            .icon {
 | 
			
		||||
              display: inline-block;
 | 
			
		||||
              width: 60px;
 | 
			
		||||
              height: 60px;
 | 
			
		||||
              line-height: 60px;
 | 
			
		||||
              border-radius: 50%;
 | 
			
		||||
              background-color: #2266ff;
 | 
			
		||||
              color: #fff;
 | 
			
		||||
              font-size: 23px;
 | 
			
		||||
              vertical-align: middle;
 | 
			
		||||
              text-align: center;
 | 
			
		||||
              // font-weight: 800;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            .my_reply {
 | 
			
		||||
              width: 370px;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            .right {
 | 
			
		||||
              color: #999;
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          .myreply_content {
 | 
			
		||||
            width: 606px;
 | 
			
		||||
            height: 460px;
 | 
			
		||||
            background-color: #f3f6f9;
 | 
			
		||||
            margin: 24px 0 0 62px;
 | 
			
		||||
            padding: 16px;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .no_more {
 | 
			
		||||
      padding: 44px 0;
 | 
			
		||||
      color: #999;
 | 
			
		||||
      font-size: 24px;
 | 
			
		||||
      text-align: center;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .close_reply {
 | 
			
		||||
    position: fixed;
 | 
			
		||||
    bottom: 0;
 | 
			
		||||
    display: flex;
 | 
			
		||||
    height: 112px;
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    border-top: 1px solid #ddd;
 | 
			
		||||
    z-index: 999;
 | 
			
		||||
    background: #fff;
 | 
			
		||||
 | 
			
		||||
    .btn {
 | 
			
		||||
      flex: 1;
 | 
			
		||||
      min-width: 0;
 | 
			
		||||
      background-color: #fff;
 | 
			
		||||
      display: flex;
 | 
			
		||||
      justify-content: center;
 | 
			
		||||
      align-items: center;
 | 
			
		||||
 | 
			
		||||
      &.reply {
 | 
			
		||||
        background-color: #1365dd;
 | 
			
		||||
        color: #fff;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										78
									
								
								src/pages/casuallyask/closemsg.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,78 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="closemsg">
 | 
			
		||||
    <img :src="imgSrc" alt="" />
 | 
			
		||||
    <text>{{ text }}</text>
 | 
			
		||||
    <u-button
 | 
			
		||||
      type="primary"
 | 
			
		||||
      :custom-style="{ width: '100%', borderRadius: '4px', marginTop: '48px' }"
 | 
			
		||||
      @click="goBack"
 | 
			
		||||
      >{{ btnText }}</u-button
 | 
			
		||||
    >
 | 
			
		||||
    <back></back>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import back from '../../components/AiBack'
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: 'CloseMsg',
 | 
			
		||||
  components: { back },
 | 
			
		||||
  data() {
 | 
			
		||||
    return {
 | 
			
		||||
      flag: true
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  onLoad(val) {
 | 
			
		||||
    if (val.flag) {
 | 
			
		||||
      this.flag = val.flag
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    goBack() {
 | 
			
		||||
      uni.navigateBack({
 | 
			
		||||
        // url: `/pages/casuallyask/casuallyask`
 | 
			
		||||
        delta: 1
 | 
			
		||||
      })
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  computed: {
 | 
			
		||||
    text() {
 | 
			
		||||
      return this.flag ? '关闭留言成功!' : '关闭留言失败'
 | 
			
		||||
    },
 | 
			
		||||
    btnText() {
 | 
			
		||||
      return this.flag ? '确定' : '查看详情'
 | 
			
		||||
    },
 | 
			
		||||
    imgSrc() {
 | 
			
		||||
      return this.flag
 | 
			
		||||
        ? this.imgOtherUrl + 'kztcg.png'
 | 
			
		||||
        : this.imgOtherUrl + 'kztsb.png'
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
.closemsg {
 | 
			
		||||
  min-height: 100%;
 | 
			
		||||
  background-color: #ffffff;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-direction: column;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  padding: 96px;
 | 
			
		||||
 | 
			
		||||
  img {
 | 
			
		||||
    width: 192px;
 | 
			
		||||
    height: 192px;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  text {
 | 
			
		||||
    font-size: 36px;
 | 
			
		||||
    font-weight: 800;
 | 
			
		||||
    color: #333333;
 | 
			
		||||
    line-height: 50px;
 | 
			
		||||
    display: flex;
 | 
			
		||||
    justify-content: center;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										197
									
								
								src/pages/casuallyask/reply.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,197 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="reply">
 | 
			
		||||
    <div class="reply_content">
 | 
			
		||||
      <span class="icon">*</span>
 | 
			
		||||
      <text class="msgfont">回复内容</text>
 | 
			
		||||
      <textarea :maxlength="500" placeholder="请输入内容(500字以内)" v-model="msg" class="textarea"></textarea>
 | 
			
		||||
      <!-- <u-input
 | 
			
		||||
        type="textarea"
 | 
			
		||||
        height="50"
 | 
			
		||||
        :auto-height="false"
 | 
			
		||||
        placeholder="请输入内容(500字以内)"
 | 
			
		||||
        placeholder-style="color:#999;"
 | 
			
		||||
        maxlength="500"
 | 
			
		||||
        v-model="msg"
 | 
			
		||||
        class="textarea"
 | 
			
		||||
      /> -->
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="reply_img">
 | 
			
		||||
      <text class="img">图片资料</text>
 | 
			
		||||
      <text class="img_text">(最多9张)</text>
 | 
			
		||||
      <div class="upload">
 | 
			
		||||
        <div class="info">
 | 
			
		||||
          <ai-uploader multiple @data="data" @change="change" :limit="9" action="/admin/file/add2"></ai-uploader>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <ai-back/>
 | 
			
		||||
    <div class="submit">
 | 
			
		||||
      <button class="btn" @click="btn">提交</button>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import AiUploader from '../../components/AiUploader'
 | 
			
		||||
import AiBack from "../../components/AiBack";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  // name: '',
 | 
			
		||||
  // 组件
 | 
			
		||||
  components: {AiBack, AiUploader},
 | 
			
		||||
  props: {},
 | 
			
		||||
  data() {
 | 
			
		||||
    return {
 | 
			
		||||
      msg: '',
 | 
			
		||||
      files: [],
 | 
			
		||||
      msgCode: '',
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  onLoad(options) {
 | 
			
		||||
    this.msgCode = options.msgCode
 | 
			
		||||
  },
 | 
			
		||||
  // 计算
 | 
			
		||||
  computed: {},
 | 
			
		||||
  // 监听
 | 
			
		||||
  watch: {},
 | 
			
		||||
  // 实例创建后
 | 
			
		||||
  onShow() {
 | 
			
		||||
    this.$dict.load('leaveMessageType').then(() => {
 | 
			
		||||
      this.dictList = this.$dict.getDict('leaveMessageType')
 | 
			
		||||
    })
 | 
			
		||||
  },
 | 
			
		||||
  // 实例渲染后
 | 
			
		||||
  mounted() {
 | 
			
		||||
  },
 | 
			
		||||
  // 方法
 | 
			
		||||
  methods: {
 | 
			
		||||
    data(e) {
 | 
			
		||||
      this.files.push(e)
 | 
			
		||||
    },
 | 
			
		||||
    // selectEventType(selecteds) {
 | 
			
		||||
    //   this.eventType = selecteds?.[0]?.value
 | 
			
		||||
    // },
 | 
			
		||||
    change(e) {
 | 
			
		||||
      this.files = e
 | 
			
		||||
    },
 | 
			
		||||
    btn() {
 | 
			
		||||
      if (this.msg == '') {
 | 
			
		||||
        return uni.showToast({
 | 
			
		||||
          title: '请输入留言内容',
 | 
			
		||||
          icon: 'none',
 | 
			
		||||
        })
 | 
			
		||||
      }
 | 
			
		||||
      this.$http
 | 
			
		||||
      .post(`/app/appleavemessagereply/addOrUpdate`, {
 | 
			
		||||
        images: JSON.stringify(this.files),
 | 
			
		||||
        content: this.msg,
 | 
			
		||||
        msgCode: this.msgCode,
 | 
			
		||||
        userType: '1',
 | 
			
		||||
      }).then(res => {
 | 
			
		||||
        if (res?.code == 0) {
 | 
			
		||||
          uni.navigateTo({
 | 
			
		||||
            url: `/pages/casuallyask/truemsg?flag=1`,
 | 
			
		||||
          })
 | 
			
		||||
        }
 | 
			
		||||
      }).catch(err => {
 | 
			
		||||
        uni.navigateTo({
 | 
			
		||||
          url: `/pages/casuallyask/truemsg?flag=0`,
 | 
			
		||||
        })
 | 
			
		||||
        this.$u.toast(err || '网络异常')
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style scoped lang="scss">
 | 
			
		||||
.reply {
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  // height: 100%;
 | 
			
		||||
  .reply_content {
 | 
			
		||||
    height: 288px;
 | 
			
		||||
    padding: 0 20px 0 20px;
 | 
			
		||||
    background-color: #fff;
 | 
			
		||||
 | 
			
		||||
    .icon {
 | 
			
		||||
      display: inline-block;
 | 
			
		||||
      width: 16px;
 | 
			
		||||
      height: 44px;
 | 
			
		||||
      line-height: 44px;
 | 
			
		||||
      font-size: 42px;
 | 
			
		||||
      vertical-align: middle;
 | 
			
		||||
      color: red;
 | 
			
		||||
      margin-top: 10px;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .msgfont {
 | 
			
		||||
      // overflow: auto;
 | 
			
		||||
      // word-wrap: break-word;
 | 
			
		||||
      // word-break: break-all;
 | 
			
		||||
      display: inline-block;
 | 
			
		||||
      width: 226px;
 | 
			
		||||
      height: 44px;
 | 
			
		||||
      margin-top: 34px;
 | 
			
		||||
      line-height: 44px;
 | 
			
		||||
      font-size: 32px;
 | 
			
		||||
      // font-weight: 800;
 | 
			
		||||
      margin-left: 10px;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .textarea {
 | 
			
		||||
      height: 190px;
 | 
			
		||||
      width: 700px;
 | 
			
		||||
      // overflow: auto;
 | 
			
		||||
      // word-wrap: break-word;
 | 
			
		||||
      // word-break: break-all;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .reply_img {
 | 
			
		||||
    margin-top: 20px;
 | 
			
		||||
    background-color: #fff;
 | 
			
		||||
    padding: 0 20px;
 | 
			
		||||
    box-sizing: border-box;
 | 
			
		||||
 | 
			
		||||
    .img {
 | 
			
		||||
      display: inline-block;
 | 
			
		||||
      margin-top: 20px;
 | 
			
		||||
      font-size: 32px;
 | 
			
		||||
      // font-weight: 800;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .img_text {
 | 
			
		||||
      font-size: 32px;
 | 
			
		||||
      color: #999;
 | 
			
		||||
      margin-left: 10px;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .upload {
 | 
			
		||||
      width: 100%;
 | 
			
		||||
      margin-top: 10px;
 | 
			
		||||
      padding: 12px 12px 12px 0;
 | 
			
		||||
      box-sizing: border-box;
 | 
			
		||||
 | 
			
		||||
      .info {
 | 
			
		||||
        width: 100%;
 | 
			
		||||
        text-align: center;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      ::v-deep .ai-uploader .fileList .default {
 | 
			
		||||
        width: 160px;
 | 
			
		||||
        height: 160px;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .submit {
 | 
			
		||||
    padding: 50px 32px;
 | 
			
		||||
 | 
			
		||||
    .btn {
 | 
			
		||||
      background-color: #1365dd;
 | 
			
		||||
      color: #fff;
 | 
			
		||||
      font-size: 36px;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										75
									
								
								src/pages/casuallyask/truemsg.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,75 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="closemsg">
 | 
			
		||||
    <img :src="imgSrc" alt=""/>
 | 
			
		||||
    <text>{{ text }}</text>
 | 
			
		||||
    <u-button
 | 
			
		||||
        type="primary"
 | 
			
		||||
        :custom-style="{ width: '100%', borderRadius: '4px', marginTop: '48px' }"
 | 
			
		||||
        @click="goBack"
 | 
			
		||||
    >{{ btnText }}
 | 
			
		||||
    </u-button>
 | 
			
		||||
    <back></back>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import back from '../../components/AiBack'
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: 'CloseMsg',
 | 
			
		||||
  components: {back},
 | 
			
		||||
  data() {
 | 
			
		||||
    return {
 | 
			
		||||
      flag: true
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  onLoad(val) {
 | 
			
		||||
    this.flag = val?.flag == 1
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    goBack() {
 | 
			
		||||
      uni.navigateBack({
 | 
			
		||||
        delta: 2
 | 
			
		||||
      })
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  computed: {
 | 
			
		||||
    text() {
 | 
			
		||||
      return this.flag ? '提交成功!' : '处理失败'
 | 
			
		||||
    },
 | 
			
		||||
    btnText() {
 | 
			
		||||
      return this.flag ? '查看详情' : '我知道了'
 | 
			
		||||
    },
 | 
			
		||||
    imgSrc() {
 | 
			
		||||
      return this.flag
 | 
			
		||||
          ? this.imgOtherUrl + 'kztcg.png'
 | 
			
		||||
          : this.imgOtherUrl + 'kztsb.png'
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
.closemsg {
 | 
			
		||||
  min-height: 100%;
 | 
			
		||||
  background-color: #ffffff;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-direction: column;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  padding: 96px;
 | 
			
		||||
 | 
			
		||||
  img {
 | 
			
		||||
    width: 192px;
 | 
			
		||||
    height: 192px;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  text {
 | 
			
		||||
    font-size: 36px;
 | 
			
		||||
    font-weight: 800;
 | 
			
		||||
    color: #333333;
 | 
			
		||||
    line-height: 50px;
 | 
			
		||||
    display: flex;
 | 
			
		||||
    justify-content: center;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										91
									
								
								src/pages/documentFlow/components/approval.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,91 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="approval">
 | 
			
		||||
    <div class="card">
 | 
			
		||||
      <header>批示意见</header>
 | 
			
		||||
      <textarea placeholder="请输入批示意见" v-model.trim="description" maxlength="200"></textarea>
 | 
			
		||||
      <u-row justify="between">
 | 
			
		||||
        <span @click="description=''">清空内容</span>
 | 
			
		||||
        <span>{{description.length || 0}}/200</span>
 | 
			
		||||
      </u-row>
 | 
			
		||||
    </div>
 | 
			
		||||
    <ai-back/>
 | 
			
		||||
    <u-button type="primary" @click="submit">提交</u-button>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
  import AiBack from "../../../components/AiBack";
 | 
			
		||||
 | 
			
		||||
  export default {
 | 
			
		||||
    name: "approval",
 | 
			
		||||
    components: {AiBack},
 | 
			
		||||
    data() {
 | 
			
		||||
      return {
 | 
			
		||||
        id: null,
 | 
			
		||||
        description: ""
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    onLoad(opt) {
 | 
			
		||||
      this.id = opt.id
 | 
			
		||||
    },
 | 
			
		||||
    methods: {
 | 
			
		||||
      submit() {
 | 
			
		||||
        this.$http.post("/app/appofficialdocumentinfo/instructionById", null, {
 | 
			
		||||
          params: {
 | 
			
		||||
            id: this.id,
 | 
			
		||||
            description: this.description
 | 
			
		||||
          }
 | 
			
		||||
        }).then(res => {
 | 
			
		||||
          if (res.code == 0) {
 | 
			
		||||
            this.$u.toast("批示成功")
 | 
			
		||||
            uni.navigateBack()
 | 
			
		||||
          }
 | 
			
		||||
        })
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
  .approval {
 | 
			
		||||
    background: #F5F5F5;
 | 
			
		||||
 | 
			
		||||
    .card {
 | 
			
		||||
      background-color: #FFFFFF;
 | 
			
		||||
      box-sizing: border-box;
 | 
			
		||||
      padding: 32px;
 | 
			
		||||
 | 
			
		||||
      header {
 | 
			
		||||
        font-size: 32px;
 | 
			
		||||
        color: #333333;
 | 
			
		||||
        margin-bottom: 16px;
 | 
			
		||||
        font-weight: bold;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      textarea {
 | 
			
		||||
        width: 100%;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      span:first-child {
 | 
			
		||||
        font-size: 28px;
 | 
			
		||||
        color: #1365DD;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      span:last-child {
 | 
			
		||||
        font-size: 24px;
 | 
			
		||||
        color: #999999;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .u-btn {
 | 
			
		||||
      width: 100%;
 | 
			
		||||
      height: 112px !important;
 | 
			
		||||
      font-size: 32px;
 | 
			
		||||
      color: #FFFFFF;
 | 
			
		||||
      position: fixed;
 | 
			
		||||
      left: 0;
 | 
			
		||||
      bottom: 0;
 | 
			
		||||
      background: #197DF0 !important;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										432
									
								
								src/pages/documentFlow/components/detail.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,432 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="detail">
 | 
			
		||||
    <template v-if="!userSelect">
 | 
			
		||||
      <div class="card">
 | 
			
		||||
        <header>{{detail.documentName}}</header>
 | 
			
		||||
        <u-gap height="16"></u-gap>
 | 
			
		||||
        <u-row>
 | 
			
		||||
          <span>公文编号:</span>
 | 
			
		||||
          <span>{{detail.documentCode}}</span>
 | 
			
		||||
        </u-row>
 | 
			
		||||
        <u-gap height="8"></u-gap>
 | 
			
		||||
        <u-row>
 | 
			
		||||
          <span>公文类型:</span>
 | 
			
		||||
          <span>{{$dict.getLabel("officialDocumentName",detail.documentType)}}</span>
 | 
			
		||||
        </u-row>
 | 
			
		||||
        <u-gap height="8"></u-gap>
 | 
			
		||||
        <u-row>
 | 
			
		||||
          <span>紧急程度:</span>
 | 
			
		||||
          <span :style="{color:$dict.getColor('documentEmergencyLevel',detail.emergencyLevel)}">{{$dict.getLabel("documentEmergencyLevel",detail.emergencyLevel)}}</span>
 | 
			
		||||
        </u-row>
 | 
			
		||||
        <u-gap height="8"></u-gap>
 | 
			
		||||
        <u-row>
 | 
			
		||||
          <span>发文机关:</span>
 | 
			
		||||
          <span>{{detail.issuingUnit}}</span>
 | 
			
		||||
        </u-row>
 | 
			
		||||
        <u-gap height="8"></u-gap>
 | 
			
		||||
        <u-row>
 | 
			
		||||
          <span>发文字号:</span>
 | 
			
		||||
          <span>{{detail.issuingFont}}</span>
 | 
			
		||||
        </u-row>
 | 
			
		||||
        <u-gap height="8"></u-gap>
 | 
			
		||||
        <u-row>
 | 
			
		||||
          <span>签发人:</span>
 | 
			
		||||
          <span>{{detail.signer}}</span>
 | 
			
		||||
        </u-row>
 | 
			
		||||
        <u-gap height="16"></u-gap>
 | 
			
		||||
        <img v-if="detail.confidentialityLevel" :src="$cdn + tag(detail.confidentialityLevel)" alt="">
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="card" style="margin-bottom: 0;padding-top: 0">
 | 
			
		||||
        <div class="label">备注</div>
 | 
			
		||||
        <span>{{detail.remark}}</span>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="card" style="padding-top: 0" v-if="detail.files && detail.files.length">
 | 
			
		||||
        <div class="label">相关附件</div>
 | 
			
		||||
        <div class="file" v-for="(item,index) in detail.files" :key="index" @click="preFile(item)">
 | 
			
		||||
          <u-row justify="between">
 | 
			
		||||
            <label class="left">
 | 
			
		||||
              <img :src="$cdn + 'common/appendix.png'" alt="">
 | 
			
		||||
              <span>{{item.fileName}}.{{item.postfix}}</span>
 | 
			
		||||
            </label>
 | 
			
		||||
            <span>{{(item.size/1024).toFixed(2)}}KB</span>
 | 
			
		||||
          </u-row>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="card">
 | 
			
		||||
        <div class="label" style="96px;">{{detail.readType ==0 ? "流转信息" : "传阅情况"}}
 | 
			
		||||
          <em>({{$dict.getLabel("documentStatus",detail.status)}})</em></div>
 | 
			
		||||
        <div class="progress">
 | 
			
		||||
          <div class="item" v-for="(item,index) in detail.flowUsers" :key="index">
 | 
			
		||||
            <div class="avatar">{{item.flowUserName && item.flowUserName.substr(-2)}}</div>
 | 
			
		||||
            <div class="right">
 | 
			
		||||
              <u-row justify="between">
 | 
			
		||||
                <text class="status" :style="{color:item.readStatus==1?'#FF8822':'#1365DD'}">{{$dict.getLabel(detail.readType ==1 ? "readingStatus" :
 | 
			
		||||
                  "documentFlowStatus",detail.readType ==0 ? item.flowStatus : item.readStatus)}}
 | 
			
		||||
                </text>
 | 
			
		||||
                <text class="date">{{item.flowTime}}</text>
 | 
			
		||||
              </u-row>
 | 
			
		||||
              <u-row justify="between">
 | 
			
		||||
                <text class="name">{{item.flowUserName}}</text>
 | 
			
		||||
              </u-row>
 | 
			
		||||
              <u-row justify="between">
 | 
			
		||||
                <text class="note">{{item.description}}</text>
 | 
			
		||||
              </u-row>
 | 
			
		||||
            </div>
 | 
			
		||||
          </div>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
 | 
			
		||||
      <div class="footer" v-if="detail.flowRight==1 && detail.readType==0">
 | 
			
		||||
        <div @click="handleClick(0)">批示</div>
 | 
			
		||||
        <div @click="handleClick(1)">流转</div>
 | 
			
		||||
      </div>
 | 
			
		||||
 | 
			
		||||
      <div class="footer" v-if="detail.readType==1 && detail.flowRight==1" @click="read" style="background-color: #1365DD;color: #FFFFFF">我已阅完</div>
 | 
			
		||||
 | 
			
		||||
    </template>
 | 
			
		||||
 | 
			
		||||
    <AiSelectEnterprise :visible.sync="userSelect" v-if="userSelect" :multiple="false"
 | 
			
		||||
                        @change="change"></AiSelectEnterprise>
 | 
			
		||||
 | 
			
		||||
    <AiBack v-if="!userSelect"/>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
  import AiBack from "../../../components/AiBack";
 | 
			
		||||
  import AiSelectEnterprise from "../../../components/AiSelectEnterprise/AiSelectEnterprise";
 | 
			
		||||
  import {mapActions} from "vuex";
 | 
			
		||||
 | 
			
		||||
  export default {
 | 
			
		||||
    name: "detail",
 | 
			
		||||
    components: {AiBack, AiSelectEnterprise},
 | 
			
		||||
    data() {
 | 
			
		||||
      return {
 | 
			
		||||
        id: null,
 | 
			
		||||
        detail: {},
 | 
			
		||||
        userSelect: false,
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    onLoad(opt) {
 | 
			
		||||
      this.$dict.load("officialDocumentName", "documentEmergencyLevel", "documentStatus", "readingStatus", "documentFlowStatus")
 | 
			
		||||
      this.id = opt.id
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    methods: {
 | 
			
		||||
      ...mapActions(['previewFile', 'injectJWeixin']),
 | 
			
		||||
      read() {
 | 
			
		||||
        this.$http.post("/app/appofficialdocumentinfo/readById", null, {
 | 
			
		||||
          params: {
 | 
			
		||||
            id: this.id
 | 
			
		||||
          }
 | 
			
		||||
        }).then(res => {
 | 
			
		||||
          if (res.code == 0) {
 | 
			
		||||
            this.$u.toast("已阅读")
 | 
			
		||||
            this.getDetail()
 | 
			
		||||
          }
 | 
			
		||||
        })
 | 
			
		||||
      },
 | 
			
		||||
      preFile(e) {
 | 
			
		||||
        if([".jpg",".png",".gif"].includes(e.postfix.toLowerCase())){
 | 
			
		||||
          uni.previewImage({
 | 
			
		||||
            current: e.url,
 | 
			
		||||
            urls: [e.url]
 | 
			
		||||
          })
 | 
			
		||||
        }else {
 | 
			
		||||
          this.previewFile({...e})
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      change(e) {
 | 
			
		||||
        this.$http.post("/app/appofficialdocumentinfo/flowById", null, {
 | 
			
		||||
          params: {
 | 
			
		||||
            flowUserId: e[0].id,
 | 
			
		||||
            flowUserName: e[0].name,
 | 
			
		||||
            id: this.id,
 | 
			
		||||
            avatar: e[0].avatar,
 | 
			
		||||
            flag: 0
 | 
			
		||||
          }
 | 
			
		||||
        }).then(res => {
 | 
			
		||||
          if (res.code == 0) {
 | 
			
		||||
            this.$u.toast("流转成功")
 | 
			
		||||
            this.getDetail()
 | 
			
		||||
          }
 | 
			
		||||
        })
 | 
			
		||||
      },
 | 
			
		||||
 | 
			
		||||
      tag(status) {
 | 
			
		||||
        return {
 | 
			
		||||
          "0": "common/mm.png",
 | 
			
		||||
          "1": "common/jm.png",
 | 
			
		||||
          "2": "common/tm.png"
 | 
			
		||||
        }[status]
 | 
			
		||||
      },
 | 
			
		||||
      getDetail() {
 | 
			
		||||
        this.$http.post("/app/appofficialdocumentinfo/queryDetailById", null, {
 | 
			
		||||
          params: {
 | 
			
		||||
            id: this.id,
 | 
			
		||||
            flag: 1
 | 
			
		||||
          }
 | 
			
		||||
        }).then(res => {
 | 
			
		||||
          if (res && res.data) {
 | 
			
		||||
            this.detail = res.data
 | 
			
		||||
          }
 | 
			
		||||
        })
 | 
			
		||||
      },
 | 
			
		||||
      handleClick(status) {
 | 
			
		||||
        if (status == 0) {
 | 
			
		||||
          uni.navigateTo({
 | 
			
		||||
            url: "/pages/documentFlow/components/approval?id=" + this.id
 | 
			
		||||
          })
 | 
			
		||||
        } else {
 | 
			
		||||
          this.userSelect = true
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    onShow() {
 | 
			
		||||
      this.getDetail()
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
  .detail {
 | 
			
		||||
    min-height: 100%;
 | 
			
		||||
    background-color: #F5F5F5;
 | 
			
		||||
    padding-bottom: 140px;
 | 
			
		||||
    position: relative;
 | 
			
		||||
 | 
			
		||||
    .card {
 | 
			
		||||
      background-color: #FFFFFF;
 | 
			
		||||
      margin-bottom: 8px;
 | 
			
		||||
      box-sizing: border-box;
 | 
			
		||||
      padding: 16px 32px;
 | 
			
		||||
      position: relative;
 | 
			
		||||
 | 
			
		||||
      header {
 | 
			
		||||
        font-size: 40px;
 | 
			
		||||
        font-weight: 600;
 | 
			
		||||
        color: #333333;
 | 
			
		||||
        line-height: 64px;
 | 
			
		||||
        letter-spacing: 1px;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .u-row {
 | 
			
		||||
        & > div {
 | 
			
		||||
          background-color: #2266FF;
 | 
			
		||||
          border-radius: 50%;
 | 
			
		||||
          text-align: center;
 | 
			
		||||
          font-size: 22px;
 | 
			
		||||
          font-weight: bold;
 | 
			
		||||
          color: #FFFFFF;
 | 
			
		||||
          display: flex;
 | 
			
		||||
          align-items: center;
 | 
			
		||||
          justify-content: center;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        & > span:first-child {
 | 
			
		||||
          font-size: 30px;
 | 
			
		||||
          color: #999999;;
 | 
			
		||||
          line-height: 48px;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        & > span:last-child {
 | 
			
		||||
          font-size: 30px;
 | 
			
		||||
          color: #343D65;
 | 
			
		||||
          margin-left: 16px;
 | 
			
		||||
          line-height: 48px;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      & > img {
 | 
			
		||||
        width: 190px;
 | 
			
		||||
        height: 190px;
 | 
			
		||||
        position: absolute;
 | 
			
		||||
        right: 0;
 | 
			
		||||
        top: 74px;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      & > span {
 | 
			
		||||
        font-size: 32px;
 | 
			
		||||
        color: #333333;
 | 
			
		||||
        line-height: 48px;
 | 
			
		||||
        letter-spacing: 1px;
 | 
			
		||||
        display: inline-block;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .label {
 | 
			
		||||
        height: 80px;
 | 
			
		||||
        font-size: 32px;
 | 
			
		||||
        color: #333333;
 | 
			
		||||
        display: flex;
 | 
			
		||||
        align-items: center;
 | 
			
		||||
        margin-bottom: 16px;
 | 
			
		||||
 | 
			
		||||
        & > em {
 | 
			
		||||
          font-style: normal;
 | 
			
		||||
          font-size: 32px;
 | 
			
		||||
          color: #1365DD;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .file {
 | 
			
		||||
        height: 128px;
 | 
			
		||||
        background: #FFFFFF;
 | 
			
		||||
        border-radius: 8px;
 | 
			
		||||
        border: 1px solid #CCCCCC;
 | 
			
		||||
        box-sizing: border-box;
 | 
			
		||||
        padding: 0 16px;
 | 
			
		||||
        margin-bottom: 32px;
 | 
			
		||||
 | 
			
		||||
        & > .u-row {
 | 
			
		||||
          height: 100%;
 | 
			
		||||
 | 
			
		||||
          .left {
 | 
			
		||||
            width: 500px;
 | 
			
		||||
            display: flex;
 | 
			
		||||
            align-items: center;
 | 
			
		||||
 | 
			
		||||
            & > img {
 | 
			
		||||
              flex-shrink: 0;
 | 
			
		||||
              width: 96px;
 | 
			
		||||
              height: 96px;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            & > span {
 | 
			
		||||
              font-size: 32px;
 | 
			
		||||
              color: #333333;
 | 
			
		||||
              display: inline-block;
 | 
			
		||||
              line-height: 44px;
 | 
			
		||||
              overflow: hidden;
 | 
			
		||||
              text-overflow: ellipsis;
 | 
			
		||||
              display:-webkit-box;
 | 
			
		||||
              -webkit-box-orient:vertical;
 | 
			
		||||
              -webkit-line-clamp:2;
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          & > span {
 | 
			
		||||
            font-size: 28px;
 | 
			
		||||
            color: #999999;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .active {
 | 
			
		||||
        background-color: #F3F6F9;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .progress {
 | 
			
		||||
        margin-top: 8px;
 | 
			
		||||
 | 
			
		||||
        .item {
 | 
			
		||||
          display: flex;
 | 
			
		||||
          align-items: center;
 | 
			
		||||
          position: relative;
 | 
			
		||||
          min-height: 136px;
 | 
			
		||||
          margin-bottom: 80px;
 | 
			
		||||
 | 
			
		||||
          .avatar {
 | 
			
		||||
            width: 80px;
 | 
			
		||||
            height: 80px;
 | 
			
		||||
            border-radius: 50%;
 | 
			
		||||
            background-color: #2266FF;
 | 
			
		||||
            font-size: 28px;
 | 
			
		||||
            color: #FFFFFF;
 | 
			
		||||
            display: flex;
 | 
			
		||||
            align-items: center;
 | 
			
		||||
            justify-content: center;
 | 
			
		||||
            flex-shrink: 0;
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          .right {
 | 
			
		||||
            width: 100%;
 | 
			
		||||
            display: flex;
 | 
			
		||||
            flex-direction: column;
 | 
			
		||||
 | 
			
		||||
            & > .u-row {
 | 
			
		||||
              margin-left: 40px;
 | 
			
		||||
 | 
			
		||||
              .status {
 | 
			
		||||
                font-size: 32px;
 | 
			
		||||
                color: #333333;
 | 
			
		||||
              }
 | 
			
		||||
 | 
			
		||||
              .date {
 | 
			
		||||
                font-size: 28px;
 | 
			
		||||
                color: #999999;
 | 
			
		||||
              }
 | 
			
		||||
 | 
			
		||||
              .name {
 | 
			
		||||
                font-size: 28px;
 | 
			
		||||
                color: #666666;
 | 
			
		||||
                margin: 8px 0;
 | 
			
		||||
              }
 | 
			
		||||
 | 
			
		||||
              .note {
 | 
			
		||||
                font-size: 28px;
 | 
			
		||||
                color: #343D65;
 | 
			
		||||
              }
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          &:after {
 | 
			
		||||
            content: "";
 | 
			
		||||
            width: 4px;
 | 
			
		||||
            height: 100%;
 | 
			
		||||
            background-color: #EEEEEE;
 | 
			
		||||
            position: absolute;
 | 
			
		||||
            left: 40px;
 | 
			
		||||
            top: 112px;
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          &:last-child:after {
 | 
			
		||||
            display: none;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .footer {
 | 
			
		||||
      height: 112px;
 | 
			
		||||
      width: 100%;
 | 
			
		||||
      position: fixed;
 | 
			
		||||
      left: 0;
 | 
			
		||||
      bottom: 0;
 | 
			
		||||
      background-color: #FFFFFF;
 | 
			
		||||
      display: flex;
 | 
			
		||||
      align-items: center;
 | 
			
		||||
      justify-content: center;
 | 
			
		||||
      font-size: 36px;
 | 
			
		||||
 | 
			
		||||
      & > div {
 | 
			
		||||
        color: #333333;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      & > div:first-child {
 | 
			
		||||
        width: 50%;
 | 
			
		||||
        height: 100%;
 | 
			
		||||
        display: flex;
 | 
			
		||||
        align-items: center;
 | 
			
		||||
        justify-content: center;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      & > div:last-child {
 | 
			
		||||
        width: 50%;
 | 
			
		||||
        height: 100%;
 | 
			
		||||
        color: #FFFFFF;
 | 
			
		||||
        display: flex;
 | 
			
		||||
        align-items: center;
 | 
			
		||||
        justify-content: center;
 | 
			
		||||
        background-color: #1365DD;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      & > label {
 | 
			
		||||
        display: flex;
 | 
			
		||||
        align-items: center;
 | 
			
		||||
        justify-content: center;
 | 
			
		||||
        background-color: #1365DD;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										166
									
								
								src/pages/documentFlow/documentFlow.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,166 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="document-flow">
 | 
			
		||||
    <ai-top-fixed>
 | 
			
		||||
      <header class="pad">
 | 
			
		||||
        <u-search placeholder="请输入公文名称" v-model="documentName" @clear="documentName='',getList()" @search="getList" clearabled :show-action="false" height="64"></u-search>
 | 
			
		||||
      </header>
 | 
			
		||||
    </ai-top-fixed>
 | 
			
		||||
    <div class="list pad" v-if="list.length">
 | 
			
		||||
      <div class="card" v-for="(item,index) in list" :key="index" @click="handleClick(item)">
 | 
			
		||||
        <u-row>
 | 
			
		||||
          <em v-if="item.redStatus==0"></em>
 | 
			
		||||
          <span>{{item.documentName}}</span>
 | 
			
		||||
        </u-row>
 | 
			
		||||
        <u-gap height="16"></u-gap>
 | 
			
		||||
        <u-row>
 | 
			
		||||
          <label>公文类型:</label>
 | 
			
		||||
          <text style="color: #1365DD;">{{$dict.getLabel("officialDocumentName",item.documentType)}}</text>
 | 
			
		||||
        </u-row>
 | 
			
		||||
        <u-gap height="8"></u-gap>
 | 
			
		||||
        <u-row>
 | 
			
		||||
          <label>登记人:</label>
 | 
			
		||||
          <text>{{item.createUserName}}</text>
 | 
			
		||||
        </u-row>
 | 
			
		||||
        <u-gap height="8"></u-gap>
 | 
			
		||||
        <u-row>
 | 
			
		||||
          <label>登记日期:</label>
 | 
			
		||||
          <text>{{item.createTime}}</text>
 | 
			
		||||
        </u-row>
 | 
			
		||||
        <img :src=" $cdn + tag(item.readType)" alt="">
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <AiEmpty v-else></AiEmpty>
 | 
			
		||||
    <u-loadmore :status="status" v-if="list.length"/>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
  import AiTopFixed from "../../components/AiTopFixed";
 | 
			
		||||
  import AiEmpty from "../../components/AiEmpty/AiEmpty";
 | 
			
		||||
 | 
			
		||||
  export default {
 | 
			
		||||
    name: "documentFlow",
 | 
			
		||||
    components: {AiTopFixed,AiEmpty},
 | 
			
		||||
    data() {
 | 
			
		||||
      return {
 | 
			
		||||
        documentName: "",
 | 
			
		||||
        current: 1,
 | 
			
		||||
        list: [],
 | 
			
		||||
        status: "加载更多"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    onLoad(){
 | 
			
		||||
      this.$dict.load("officialDocumentName")
 | 
			
		||||
    },
 | 
			
		||||
    methods: {
 | 
			
		||||
      tag(status){
 | 
			
		||||
        return {
 | 
			
		||||
          "0": 'common/1ps.png',
 | 
			
		||||
          "1": 'common/2cy.png'
 | 
			
		||||
        }[status]
 | 
			
		||||
      },
 | 
			
		||||
      getList() {
 | 
			
		||||
        this.$http.post("/app/appofficialdocumentinfo/appList", null, {
 | 
			
		||||
          params:{
 | 
			
		||||
            documentName: this.documentName,
 | 
			
		||||
            size: 10,
 | 
			
		||||
            current: this.current
 | 
			
		||||
          }
 | 
			
		||||
        }).then(res => {
 | 
			
		||||
          if (res && res.data) {
 | 
			
		||||
            if (this.current > 1 && this.current > res.data.pages) {
 | 
			
		||||
              this.status = "已经到底啦"
 | 
			
		||||
            }
 | 
			
		||||
            this.list = this.current > 1 ? [...this.list, ...res.data.records] : res.data.records
 | 
			
		||||
          }
 | 
			
		||||
        })
 | 
			
		||||
      },
 | 
			
		||||
      handleClick({id}) {
 | 
			
		||||
        uni.navigateTo({
 | 
			
		||||
          url: "/pages/documentFlow/components/detail?id=" + id
 | 
			
		||||
        })
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    onShow(){
 | 
			
		||||
      this.getList()
 | 
			
		||||
    },
 | 
			
		||||
    onReachBottom() {
 | 
			
		||||
      this.current = this.current + 1;
 | 
			
		||||
      this.getList()
 | 
			
		||||
    },
 | 
			
		||||
  }
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
  .document-flow {
 | 
			
		||||
    min-height: 100%;
 | 
			
		||||
    background: #F5F5F5;
 | 
			
		||||
 | 
			
		||||
    ::v-deep .content {
 | 
			
		||||
      padding: 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    header {
 | 
			
		||||
      height: 112px;
 | 
			
		||||
      background-color: #FFFFFF;
 | 
			
		||||
      display: flex;
 | 
			
		||||
      align-items: center;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .list {
 | 
			
		||||
      margin: 32px 0;
 | 
			
		||||
 | 
			
		||||
      .card {
 | 
			
		||||
        background: #FFFFFF;
 | 
			
		||||
        border-radius: 8px;
 | 
			
		||||
        box-sizing: border-box;
 | 
			
		||||
        padding: 32px;
 | 
			
		||||
        position: relative;
 | 
			
		||||
        margin-bottom: 32px;
 | 
			
		||||
 | 
			
		||||
        .u-row{
 | 
			
		||||
          flex-wrap: nowrap !important;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        em {
 | 
			
		||||
          width: 16px;
 | 
			
		||||
          height: 16px;
 | 
			
		||||
          border-radius: 50%;
 | 
			
		||||
          background-color: #FF4466;
 | 
			
		||||
          font-style: normal;
 | 
			
		||||
          margin-right: 8px;
 | 
			
		||||
          flex-shrink: 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        span {
 | 
			
		||||
          font-size: 32px;
 | 
			
		||||
          font-weight: 600;
 | 
			
		||||
          color: #333333;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        label {
 | 
			
		||||
          font-size: 30px;
 | 
			
		||||
          color: #999999;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        text {
 | 
			
		||||
          font-size: 30px;
 | 
			
		||||
          color: #343D65;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        img {
 | 
			
		||||
          width: 160px;
 | 
			
		||||
          height: 160px;
 | 
			
		||||
          position: absolute;
 | 
			
		||||
          right: 0;
 | 
			
		||||
          bottom: 0;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .pad {
 | 
			
		||||
      box-sizing: border-box;
 | 
			
		||||
      padding: 32px 32px 0 32px;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										146
									
								
								src/pages/guardianship/component/areaSelector.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,146 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <section class="areaSelector">
 | 
			
		||||
    <ai-search-popup mode="bottom" ref="areaSelector">
 | 
			
		||||
      <template #btn>
 | 
			
		||||
        <div class="areaSelector">
 | 
			
		||||
          <span v-for="area in fullArea" :key="area.id" v-text="area.name"
 | 
			
		||||
                :class="{current:area.id==areaId}"  @tap="index=area.id,getChildAreas(area.id)"/>
 | 
			
		||||
        </div>
 | 
			
		||||
      </template>
 | 
			
		||||
      <div class="areaSelector">
 | 
			
		||||
        <span v-for="area in fullArea" :key="area.id" v-text="area.name"
 | 
			
		||||
              :class="{current:area.id==index}"
 | 
			
		||||
              @click="index=area.id,getChildAreas(area.id)"/>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="pendingItem" flex v-for="op in list" :key="op.id" @tap="handleSelect(op)">
 | 
			
		||||
        <div class="fill" :class="{self:index==op.id}" v-html="op.name"/>
 | 
			
		||||
        <u-icon name="arrow-right" color="#ddd"/>
 | 
			
		||||
      </div>
 | 
			
		||||
    </ai-search-popup>
 | 
			
		||||
  </section>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import AiSearchPopup from "../../../components/AiSearchPopup";
 | 
			
		||||
import AiCell from "../../../components/AiCell";
 | 
			
		||||
import {mapState} from "vuex";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: "areaSelector",
 | 
			
		||||
  components: {AiCell, AiSearchPopup},
 | 
			
		||||
  props: {
 | 
			
		||||
    areaId: {default: ""}
 | 
			
		||||
  },
 | 
			
		||||
  computed: {
 | 
			
		||||
    ...mapState(['user']),
 | 
			
		||||
    dataRange() {
 | 
			
		||||
      let rules = [10, 8, 6, 3, 0], level = 2
 | 
			
		||||
      rules.some((e, i) => {
 | 
			
		||||
        let reg = new RegExp(`0{${e}}`, 'g')
 | 
			
		||||
        if (reg.test(this.user.areaId)) {
 | 
			
		||||
          return level = i
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
      return level
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  data() {
 | 
			
		||||
    return {
 | 
			
		||||
      fullArea: [],
 | 
			
		||||
      index: "",
 | 
			
		||||
      list: []
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  watch: {
 | 
			
		||||
    areaId(v) {
 | 
			
		||||
      v && this.getFullArea()
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    getFullArea() {
 | 
			
		||||
      let {areaId} = this
 | 
			
		||||
      return areaId && this.$http.post("/admin/area/getAllParentAreaId", null, {
 | 
			
		||||
        params: {areaId}
 | 
			
		||||
      }).then(res => {
 | 
			
		||||
        if (res?.data) {
 | 
			
		||||
          this.fullArea = res.data.reverse().slice(this.dataRange)
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
    getChildAreas(id) {
 | 
			
		||||
      id && this.$http.post("/admin/area/queryAreaByParentId", null, {
 | 
			
		||||
        params: {id}
 | 
			
		||||
      }).then(res => {
 | 
			
		||||
        if (res?.data) {
 | 
			
		||||
          this.list = res.data
 | 
			
		||||
          let self = this.fullArea.find(e => e.id == this.index)
 | 
			
		||||
          this.list.unshift(self)
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
    handleSelect(op) {
 | 
			
		||||
      this.$emit('select', op)
 | 
			
		||||
      this.$refs.areaSelector?.handleSelect()
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  created() {
 | 
			
		||||
    this.index = this.areaId
 | 
			
		||||
    this.getFullArea()
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
.areaSelector {
 | 
			
		||||
  ::v-deep .AiSearchPopup {
 | 
			
		||||
    .areaSelector {
 | 
			
		||||
      display: flex;
 | 
			
		||||
      align-items: center;
 | 
			
		||||
 | 
			
		||||
      span {
 | 
			
		||||
        cursor: pointer;
 | 
			
		||||
 | 
			
		||||
        &:first-of-type:before {
 | 
			
		||||
          content: "";
 | 
			
		||||
          padding: 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        &:before {
 | 
			
		||||
          color: #333;
 | 
			
		||||
          content: "/";
 | 
			
		||||
          padding: 0 16px;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .current {
 | 
			
		||||
        color: #3F8DF5;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .u-drawer-content {
 | 
			
		||||
      position: fixed;
 | 
			
		||||
 | 
			
		||||
      .areaSelector {
 | 
			
		||||
        padding: 0 16px;
 | 
			
		||||
        box-sizing: border-box;
 | 
			
		||||
        border-bottom: 16px solid #f5f5f5;
 | 
			
		||||
 | 
			
		||||
        span {
 | 
			
		||||
          line-height: 100px;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .pendingItem {
 | 
			
		||||
      margin-left: 32px;
 | 
			
		||||
      padding-right: 32px;
 | 
			
		||||
      height: 104px;
 | 
			
		||||
      border-bottom: 1px solid #ddd;
 | 
			
		||||
 | 
			
		||||
      .self {
 | 
			
		||||
        font-weight: bold;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										73
									
								
								src/pages/guardianship/component/makeCalls.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,73 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <section class="makeCalls">
 | 
			
		||||
    <div v-if="$slots.default" @tap="calls=true">
 | 
			
		||||
      <slot/>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div v-else flex class="column" @tap="calls=true">
 | 
			
		||||
      <img :src="`${$cdn}guardianship/dh.png`"/>
 | 
			
		||||
      <span v-html="label"/>
 | 
			
		||||
    </div>
 | 
			
		||||
    <u-popup v-model="calls" mode="bottom">
 | 
			
		||||
      <div flex class="column option" v-for="item in list" @click="handleCall(item.guardianPhone)">
 | 
			
		||||
        {{ [item.guardianName, item.guardianPhone].join('   ') }}
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="option" @tap="calls=false">取消</div>
 | 
			
		||||
    </u-popup>
 | 
			
		||||
  </section>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
export default {
 | 
			
		||||
  name: "makeCalls",
 | 
			
		||||
  props: {
 | 
			
		||||
    label: {default: "联系ta"},
 | 
			
		||||
    list: {default: () => []}
 | 
			
		||||
  },
 | 
			
		||||
  data() {
 | 
			
		||||
    return {
 | 
			
		||||
      calls: false
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    handleCall(phone) {
 | 
			
		||||
      location.href = "tel:" + phone
 | 
			
		||||
    },
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
.makeCalls {
 | 
			
		||||
  img {
 | 
			
		||||
    width: 40px;
 | 
			
		||||
    height: 40px;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ::v-deep span {
 | 
			
		||||
    margin-left: 0;
 | 
			
		||||
    color: #999;
 | 
			
		||||
    font-size: 20px;
 | 
			
		||||
 | 
			
		||||
    p {
 | 
			
		||||
      color: #3D94FB;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ::v-deep .u-drawer {
 | 
			
		||||
    text-align: center;
 | 
			
		||||
    .uni-scroll-view-content{
 | 
			
		||||
      max-height: 672px;
 | 
			
		||||
    }
 | 
			
		||||
    .option {
 | 
			
		||||
      font-size: 32px;
 | 
			
		||||
      cursor: pointer;
 | 
			
		||||
      line-height: 112px;
 | 
			
		||||
      border-bottom: 1px solid #D8DDE6;
 | 
			
		||||
 | 
			
		||||
      &:first-of-type {
 | 
			
		||||
        border-radius: 16px 16px 0 0;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										40
									
								
								src/pages/guardianship/component/openMap.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,40 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <section class="openMap">
 | 
			
		||||
    <div flex class="column" shrink @tap="handleOpenMap">
 | 
			
		||||
      <img :src="`${$cdn}guardianship/seat.png`"/>
 | 
			
		||||
      <span v-text="'地图/导航'"/>
 | 
			
		||||
    </div>
 | 
			
		||||
  </section>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
export default {
 | 
			
		||||
  name: "openMap",
 | 
			
		||||
  props: {
 | 
			
		||||
    data: {default: () => ({})}
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    handleOpenMap() {
 | 
			
		||||
      let {lng, lat, gpsDesc} = this.data
 | 
			
		||||
      location.href = `https://uri.amap.com/marker?callnative=1&position=${[lng, lat].toString()}&name=${gpsDesc}`
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
.openMap {
 | 
			
		||||
  flex-shrink: 0;
 | 
			
		||||
 | 
			
		||||
  img {
 | 
			
		||||
    width: 40px;
 | 
			
		||||
    height: 40px;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  span {
 | 
			
		||||
    margin-left: 0;
 | 
			
		||||
    color: #999;
 | 
			
		||||
    font-size: 20px;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										169
									
								
								src/pages/guardianship/earlyWarning.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,169 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <section class="earlyWarning">
 | 
			
		||||
    <ai-top-fixed>
 | 
			
		||||
      <u-search v-model="search.name" placeholder="请输入姓名" :show-action="false"
 | 
			
		||||
                search-icon-color="#ccc" placeholder-color="#999"
 | 
			
		||||
                @change="page.current=1,getList()"/>
 | 
			
		||||
      <div flex>
 | 
			
		||||
        <ai-date class="fill" placeholder="日期选择" mode="range" @change="handleDateSearch"/>
 | 
			
		||||
        <ai-select class="fill" dict="intelligentGuardianshipItem2" @data="handleTypeSearch">
 | 
			
		||||
          <div>{{ $dict.getLabel('intelligentGuardianshipItem2', search.item) || '全部预警' }}</div>
 | 
			
		||||
          <i class="iconfont iconfont-iconArrow_Down"/>
 | 
			
		||||
        </ai-select>
 | 
			
		||||
      </div>
 | 
			
		||||
    </ai-top-fixed>
 | 
			
		||||
    <div class="card" v-for="row in list" :key="row.id" @tap="handleShow(row)">
 | 
			
		||||
      <div class="header" flex>
 | 
			
		||||
        <img :src="top.cdn(typeIcons[row.item])"/>
 | 
			
		||||
        <b v-text="row.desc"/>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="wrapper">
 | 
			
		||||
        <div class="start" flex>
 | 
			
		||||
          <span v-text="`上报时间:`"/>
 | 
			
		||||
          <div v-text="row.createTime"/>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="start" flex>
 | 
			
		||||
          <span v-text="`上报地点:`"/>
 | 
			
		||||
          <div v-text="row.gpsDesc"/>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
  </section>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import AiTopFixed from "../../components/AiTopFixed";
 | 
			
		||||
import {mapState} from "vuex";
 | 
			
		||||
import AiDate from "../../components/AiDate";
 | 
			
		||||
import AiSelect from "../../components/AiSelect";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: "earlyWarning",
 | 
			
		||||
  components: {AiSelect, AiDate, AiTopFixed},
 | 
			
		||||
  inject: ['top'],
 | 
			
		||||
  computed: {
 | 
			
		||||
    ...mapState(['user']),
 | 
			
		||||
    typeIcons() {
 | 
			
		||||
      return {
 | 
			
		||||
        0: "icon4",
 | 
			
		||||
        1: "icon2",
 | 
			
		||||
        2: "icon5",
 | 
			
		||||
        3: "icon6",
 | 
			
		||||
        4: "icon3",
 | 
			
		||||
        5: "icon1",
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  data() {
 | 
			
		||||
    return {
 | 
			
		||||
      search: {name: "", createTimeRange: ",", item: ""},
 | 
			
		||||
      areaId: "",
 | 
			
		||||
      page: {current: 1, size: 10, total: 0},
 | 
			
		||||
      list: []
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    getList() {
 | 
			
		||||
      let {areaId} = this
 | 
			
		||||
      this.$http.post("/app/appintelligentguardianshipalarm/list", null, {
 | 
			
		||||
        params: {areaId, ...this.search, ...this.page}
 | 
			
		||||
      }).then(res => {
 | 
			
		||||
        if (res?.data) {
 | 
			
		||||
          let data = res.data.records.map(e => {
 | 
			
		||||
            return {...e, desc: [e.name, this.$dict.getLabel('intelligentGuardianshipItem2', e.item)].join('的')}
 | 
			
		||||
          })
 | 
			
		||||
          if (this.page.current > 1) {
 | 
			
		||||
            this.list = [...this.list, ...data]
 | 
			
		||||
          } else this.list = data
 | 
			
		||||
          this.page.total = res.data.total
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
    reachBottom() {
 | 
			
		||||
      if (this.page.total > this.list.length) {
 | 
			
		||||
        this.page.current++
 | 
			
		||||
        this.getList()
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    handleDateSearch(v) {
 | 
			
		||||
      let {startDate: start, endDate: end} = v
 | 
			
		||||
      start = this.$dateFormat(start)
 | 
			
		||||
      end = this.$dateFormat(end)
 | 
			
		||||
      this.search.createTimeRange = [start, end || start].toString()
 | 
			
		||||
      this.page.current = 1
 | 
			
		||||
      this.getList()
 | 
			
		||||
    },
 | 
			
		||||
    handleTypeSearch(v) {
 | 
			
		||||
      this.search.item = v?.[0]?.value
 | 
			
		||||
      this.page.current = 1
 | 
			
		||||
      this.getList()
 | 
			
		||||
    },
 | 
			
		||||
    handleShow(row) {
 | 
			
		||||
      uni.navigateTo({url: `./warningDetail?id=${row.id}`})
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  created() {
 | 
			
		||||
    this.areaId = JSON.parse(JSON.stringify(this.user.areaId))
 | 
			
		||||
    this.getList()
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
.earlyWarning {
 | 
			
		||||
  padding-bottom: 130px;
 | 
			
		||||
  background: #f5f5f5;
 | 
			
		||||
 | 
			
		||||
  ::v-deep .AiDate > div {
 | 
			
		||||
    justify-content: center;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ::v-deep .u-drawer-content {
 | 
			
		||||
    padding-bottom: 100px;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ::v-deep .display {
 | 
			
		||||
    justify-content: center;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ::v-deep .iconfont-iconArrow_Down {
 | 
			
		||||
    margin-left: 4px;
 | 
			
		||||
    font-size: 32px;
 | 
			
		||||
    color: inherit;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ::v-deep .card {
 | 
			
		||||
    margin: 32px 32px 0;
 | 
			
		||||
    background: #FFFFFF;
 | 
			
		||||
    box-shadow: 0 8px 16px 0 rgba(0, 0, 0, 0.02);
 | 
			
		||||
    border-radius: 8px;
 | 
			
		||||
 | 
			
		||||
    .header {
 | 
			
		||||
      padding: 0 32px;
 | 
			
		||||
      height: 104px;
 | 
			
		||||
      border-bottom: 2px solid #EFEFF4;
 | 
			
		||||
      font-size: 36px;
 | 
			
		||||
 | 
			
		||||
      img {
 | 
			
		||||
        width: 64px;
 | 
			
		||||
        height: 64px;
 | 
			
		||||
        margin-right: 16px;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .wrapper {
 | 
			
		||||
      color: #343D65;
 | 
			
		||||
      font-size: 30px;
 | 
			
		||||
      margin-bottom: 8px;
 | 
			
		||||
      padding: 18px 32px;
 | 
			
		||||
 | 
			
		||||
      span {
 | 
			
		||||
        white-space: nowrap;
 | 
			
		||||
        flex-shrink: 0;
 | 
			
		||||
        color: #999;
 | 
			
		||||
        margin-right: 20px;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										461
									
								
								src/pages/guardianship/gsLocation.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,461 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <section class="gsLocation">
 | 
			
		||||
    <ai-map class="fill" :map.sync="amap" :lib.sync="mapLib"/>
 | 
			
		||||
    <div class="searchZone">
 | 
			
		||||
      <u-search v-model="search" placeholder="请输入姓名" shape="square" bg-color="#fff"
 | 
			
		||||
                :show-action="false" @search="getList()"/>
 | 
			
		||||
      <div class="searchResult" v-if="searchResult">
 | 
			
		||||
        <div class="item" v-for="row in list" :key="row.id" @tap="handleSelect(row)">
 | 
			
		||||
          <img :src="cdn(row.onlineStatus==1?'zxtx':'lxtx')"/>
 | 
			
		||||
          <div flex class="column fill">
 | 
			
		||||
            <b v-html="searchName(row.name)"/>
 | 
			
		||||
            <div v-text="row.gpsDesc"/>
 | 
			
		||||
          </div>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
      <u-popup v-model="popup" mode="bottom" :mask="false">
 | 
			
		||||
        <div class="headerIcon" flex @touchstart="handleTouchStart" @touchmove="handleTouchmoveClose"/>
 | 
			
		||||
        <div class="selectedInfo">
 | 
			
		||||
          <div class="header" flex>
 | 
			
		||||
            <img :src="`${$cdn}guardianship/tx.png`" @tap="handleShowDetail(selected)"/>
 | 
			
		||||
            <b v-text="selected.name" @tap="handleShowDetail(selected)"/>
 | 
			
		||||
            <div v-if="selected.abnormalStatus==1" class="abnormal" @tap="handleShowDetail(selected)">异常</div>
 | 
			
		||||
            <u-icon name="arrow-right" color="#ddd" class="fill" @tap="handleShowDetail(selected)"/>
 | 
			
		||||
            <make-calls :list="phoneList"/>
 | 
			
		||||
          </div>
 | 
			
		||||
          <div flex class="spb wrap">
 | 
			
		||||
            <div class="detail" v-for="(op,i) in quotas" :key="i" flex>
 | 
			
		||||
              <img :src="op.icon"/>
 | 
			
		||||
              <div class="fill" v-text="op.label"/>
 | 
			
		||||
              <div :class="{abnormal:op.abnormal}" v-text="op.value"/>
 | 
			
		||||
            </div>
 | 
			
		||||
          </div>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="navigation">
 | 
			
		||||
          <div class="content" flex>
 | 
			
		||||
            <div flex class="spb wrap">
 | 
			
		||||
              <div class="fill" v-text="selected.gpsDesc"/>
 | 
			
		||||
              <span>最后更新:{{ selected.lastUpdateTime }}</span>
 | 
			
		||||
              <div class="battery" flex>
 | 
			
		||||
                <img :src="batteryIcon"/>
 | 
			
		||||
                <div v-text="`剩余${selected.electricQuantity}%`"/>
 | 
			
		||||
              </div>
 | 
			
		||||
            </div>
 | 
			
		||||
            <open-map :data="selected"/>
 | 
			
		||||
          </div>
 | 
			
		||||
        </div>
 | 
			
		||||
      </u-popup>
 | 
			
		||||
    </div>
 | 
			
		||||
  </section>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import AiSearchPopup from "../../components/AiSearchPopup";
 | 
			
		||||
import {mapState} from "vuex";
 | 
			
		||||
import UPopup from "../../uview/components/u-popup/u-popup";
 | 
			
		||||
import MakeCalls from "./component/makeCalls";
 | 
			
		||||
import OpenMap from "./component/openMap";
 | 
			
		||||
import AiMap from "../../components/AiMap";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: "gsLocation",
 | 
			
		||||
  components: {AiMap, OpenMap, MakeCalls, UPopup, AiSearchPopup},
 | 
			
		||||
  computed: {
 | 
			
		||||
    ...mapState(['user']),
 | 
			
		||||
    markers() {
 | 
			
		||||
      return this.list.filter(e => e.lng).map(e => {
 | 
			
		||||
        let abnormal = 'offline'
 | 
			
		||||
        if (e.onlineStatus == 1) {
 | 
			
		||||
          switch (e.abnormalStatus) {
 | 
			
		||||
            case '1':
 | 
			
		||||
              abnormal = 'warning';
 | 
			
		||||
              break;
 | 
			
		||||
            case '2':
 | 
			
		||||
              abnormal = 'abnormal';
 | 
			
		||||
              break;
 | 
			
		||||
            default:
 | 
			
		||||
              abnormal = ''
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
        return new this.mapLib.Marker({
 | 
			
		||||
          position: new this.mapLib.LngLat(e.lng, e.lat),
 | 
			
		||||
          anchor: 'bottom-center',
 | 
			
		||||
          content: `<div class="marker ${abnormal}">${e.name}</div>`,
 | 
			
		||||
          extData: e,
 | 
			
		||||
          topWhenClick: true
 | 
			
		||||
        }).on('click', () => {
 | 
			
		||||
          this.handleSelect(e)
 | 
			
		||||
        })
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
    quotas() {
 | 
			
		||||
      let quota = [
 | 
			
		||||
        {key: "0", icon: "1"},
 | 
			
		||||
        {key: "1", icon: "2"},
 | 
			
		||||
        {key: "2", icon: "3"},
 | 
			
		||||
        {key: "3", icon: "4"},
 | 
			
		||||
      ]
 | 
			
		||||
      return quota.map(e => {
 | 
			
		||||
        let item = this.detail.find(d => d.item == e.key)
 | 
			
		||||
        let label = this.$dict.getLabel('intelligentGuardianshipItem', e.key)
 | 
			
		||||
        return {
 | 
			
		||||
          label, icon: this.cdn(e.icon),
 | 
			
		||||
          value: item?.itemValue || "-",
 | 
			
		||||
          abnormal: item?.abnormalStatus == 1
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
    batteryIcon() {
 | 
			
		||||
      return this.cdn(this.selected.electricQuantity == 100 ? 'dcm' : 'dcq')
 | 
			
		||||
    },
 | 
			
		||||
    phoneList() {
 | 
			
		||||
      let {name: guardianName, phone: guardianPhone} = this.selected
 | 
			
		||||
      return [{guardianName, guardianPhone}, ...(this.selected.guardians || [])]
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  data() {
 | 
			
		||||
    return {
 | 
			
		||||
      mapLib: null,
 | 
			
		||||
      amap: null,
 | 
			
		||||
      search: "",
 | 
			
		||||
      selected: {},
 | 
			
		||||
      list: [],
 | 
			
		||||
      popup: false,//被监护人信息弹窗
 | 
			
		||||
      detail: [],
 | 
			
		||||
      moveDistance: 0,
 | 
			
		||||
      searchResult: false //搜索下拉弹窗
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  watch: {
 | 
			
		||||
    amap(v) {
 | 
			
		||||
      v && this.getList().then(() => {
 | 
			
		||||
        this.amap?.add(this.markers)
 | 
			
		||||
        this.getMapArea()
 | 
			
		||||
      })
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    cdn(icon) {
 | 
			
		||||
      return `${this.$cdn}guardianship/${icon}.png`
 | 
			
		||||
    },
 | 
			
		||||
    getMapArea() {
 | 
			
		||||
      if (this.mapLib) {
 | 
			
		||||
        new this.mapLib.DistrictSearch({
 | 
			
		||||
          subdistrict: 0,   //获取边界不需要返回下级行政区
 | 
			
		||||
          extensions: 'all',  //返回行政区边界坐标组等具体信息
 | 
			
		||||
          level: 'district'  //查询行政级别为 市
 | 
			
		||||
        }).search(this.user.areaId.substring(0, 6), (status, result) => {
 | 
			
		||||
          let bounds = result?.districtList?.[0]?.boundaries;
 | 
			
		||||
          let polygons = []
 | 
			
		||||
          bounds?.forEach(path => polygons.push(new this.mapLib.Polygon({
 | 
			
		||||
            strokeWeight: 1,
 | 
			
		||||
            path,
 | 
			
		||||
            strokeStyle: 'dashed',
 | 
			
		||||
            fillOpacity: 0.1,
 | 
			
		||||
            fillColor: '#80d8ff',
 | 
			
		||||
            strokeColor: '#0091ea'
 | 
			
		||||
          })))
 | 
			
		||||
          this.amap.add(polygons)
 | 
			
		||||
          this.amap.setFitView();//视口自适应
 | 
			
		||||
        })
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    getList() {
 | 
			
		||||
      this.searchResult = !!this.search
 | 
			
		||||
      return this.$http.post("/app/appintelligentguardianshipdevice/list", null, {
 | 
			
		||||
        params: {name: this.search, size: 999, areaId: this.user.areaId}
 | 
			
		||||
      }).then(res => {
 | 
			
		||||
        if (res?.data) {
 | 
			
		||||
          this.list = res.data.records
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
    getDetail(deviceId) {
 | 
			
		||||
      this.$http.post("/app/appintelligentguardianshipdevice/queryMonitorList", null, {
 | 
			
		||||
        params: {type: 1, deviceId}
 | 
			
		||||
      }).then(res => {
 | 
			
		||||
        if (res?.data) {
 | 
			
		||||
          this.detail = res.data.records
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
      this.$http.post("/app/appintelligentguardianshipdevice/queryDetailById", null, {
 | 
			
		||||
        params: {id: deviceId}
 | 
			
		||||
      }).then(res => {
 | 
			
		||||
        if (res?.data) {
 | 
			
		||||
          this.selected = {...this.selected, ...res.data}
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
    searchName(name) {
 | 
			
		||||
      return name?.replace(this.search, `<span>${this.search}</span>`)
 | 
			
		||||
    },
 | 
			
		||||
    handleSelect(e) {
 | 
			
		||||
      this.amap.setCenter(new this.mapLib.LngLat(e.lng, e.lat))
 | 
			
		||||
      this.selected = e
 | 
			
		||||
      this.popup = true
 | 
			
		||||
      this.searchResult = false
 | 
			
		||||
      this.getDetail(e.id)
 | 
			
		||||
    },
 | 
			
		||||
    handleShowDetail(user) {
 | 
			
		||||
      uni.navigateTo({url: `./userDetail?id=${user.id}`})
 | 
			
		||||
    },
 | 
			
		||||
    handleTouchmoveClose(e) {
 | 
			
		||||
      if (e.touches?.[0]?.clientY > this.moveDistance + 10) {
 | 
			
		||||
        this.popup = false
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    handleTouchStart(e) {
 | 
			
		||||
      this.moveDistance = e.touches?.[0]?.clientY
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
.gsLocation {
 | 
			
		||||
  height: 100%;
 | 
			
		||||
 | 
			
		||||
  a {
 | 
			
		||||
    color: inherit;
 | 
			
		||||
    text-decoration: none;
 | 
			
		||||
    display: flex;
 | 
			
		||||
    align-items: center;
 | 
			
		||||
    justify-content: center;
 | 
			
		||||
    height: 112px;
 | 
			
		||||
    border-top: 1px solid #d8dde6;
 | 
			
		||||
 | 
			
		||||
    &:first-of-type {
 | 
			
		||||
      border-top: none;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .headerIcon {
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    height: 60px;
 | 
			
		||||
    justify-content: center;
 | 
			
		||||
 | 
			
		||||
    &:before {
 | 
			
		||||
      content: " ";
 | 
			
		||||
      display: block;
 | 
			
		||||
      width: 64px;
 | 
			
		||||
      height: 10px;
 | 
			
		||||
      background: #CCCCCC;
 | 
			
		||||
      border-radius: 5px;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ::v-deep .makeCalls {
 | 
			
		||||
    .option:last-of-type {
 | 
			
		||||
      margin-bottom: 120px;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ::v-deep .selectedInfo {
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    border-radius: 20px 20px 0 0;
 | 
			
		||||
    padding: 0 32px;
 | 
			
		||||
    background: #fff;
 | 
			
		||||
    overflow: hidden;
 | 
			
		||||
    box-sizing: border-box;
 | 
			
		||||
 | 
			
		||||
    .header {
 | 
			
		||||
      margin-bottom: 40px;
 | 
			
		||||
      font-size: 40px;
 | 
			
		||||
 | 
			
		||||
      & > img {
 | 
			
		||||
        width: 82px;
 | 
			
		||||
        height: 82px;
 | 
			
		||||
        margin-right: 16px;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .abnormal {
 | 
			
		||||
        color: #FF4466;
 | 
			
		||||
        font-size: 24px;
 | 
			
		||||
        padding: 12px;
 | 
			
		||||
        background: rgba(#EC4461, .1);
 | 
			
		||||
        border-radius: 8px;
 | 
			
		||||
        margin: 0 16px;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      span {
 | 
			
		||||
        margin-left: 0;
 | 
			
		||||
        color: #999;
 | 
			
		||||
        font-size: 20px;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .detail {
 | 
			
		||||
      width: 318px;
 | 
			
		||||
      height: 84px;
 | 
			
		||||
      background: #F4F5F6;
 | 
			
		||||
      border-radius: 8px;
 | 
			
		||||
      padding: 0 24px;
 | 
			
		||||
      box-sizing: border-box;
 | 
			
		||||
      margin-bottom: 36px;
 | 
			
		||||
 | 
			
		||||
      img {
 | 
			
		||||
        margin-right: 16px;
 | 
			
		||||
        width: 56px;
 | 
			
		||||
        height: 56px;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .abnormal {
 | 
			
		||||
        color: #FF4466;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .navigation {
 | 
			
		||||
    padding-bottom: 100px;
 | 
			
		||||
 | 
			
		||||
    .content {
 | 
			
		||||
      padding: 32px 40px;
 | 
			
		||||
      font-size: 26px;
 | 
			
		||||
 | 
			
		||||
      & > .spb {
 | 
			
		||||
        margin-right: 40px;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .fill {
 | 
			
		||||
        min-width: 100%;
 | 
			
		||||
        flex-shrink: 0;
 | 
			
		||||
        margin-bottom: 10px;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      span {
 | 
			
		||||
        margin-left: 0;
 | 
			
		||||
        color: #999;
 | 
			
		||||
        font-size: 22px;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .battery > img {
 | 
			
		||||
        margin-right: 14px;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    &:before {
 | 
			
		||||
      content: " ";
 | 
			
		||||
      display: block;
 | 
			
		||||
      width: 100%;
 | 
			
		||||
      height: 8px;
 | 
			
		||||
      background: #F4F5F6;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ::v-deep .searchZone {
 | 
			
		||||
    position: absolute;
 | 
			
		||||
    top: 0;
 | 
			
		||||
    z-index: 2;
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    background: transparent;
 | 
			
		||||
    padding: 24px 16px;
 | 
			
		||||
    box-sizing: border-box;
 | 
			
		||||
 | 
			
		||||
    .u-search {
 | 
			
		||||
      box-shadow: 0 4px 8px 0 rgba(192, 185, 185, 0.5);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .searchResult {
 | 
			
		||||
      margin-top: 16px;
 | 
			
		||||
      padding: 0 28px;
 | 
			
		||||
      background: #fff;
 | 
			
		||||
 | 
			
		||||
      .item {
 | 
			
		||||
        font-size: 24px;
 | 
			
		||||
        display: flex;
 | 
			
		||||
        line-height: 36px;
 | 
			
		||||
        padding: 24px 0;
 | 
			
		||||
        border-bottom: 3px solid #DEDFE1;
 | 
			
		||||
 | 
			
		||||
        &:last-of-type {
 | 
			
		||||
          border-bottom: none;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        img {
 | 
			
		||||
          width: 36px;
 | 
			
		||||
          height: 36px;
 | 
			
		||||
          margin-right: 16px;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        & > .fill {
 | 
			
		||||
          align-items: unset;
 | 
			
		||||
 | 
			
		||||
          b > span {
 | 
			
		||||
            color: #1365DD;
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          & > div {
 | 
			
		||||
            width: 100%;
 | 
			
		||||
            overflow: hidden;
 | 
			
		||||
            text-overflow: ellipsis;
 | 
			
		||||
            white-space: nowrap;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ::v-deep .marker {
 | 
			
		||||
    color: #fff;
 | 
			
		||||
    font-size: 30px;
 | 
			
		||||
    display: flex;
 | 
			
		||||
    justify-content: center;
 | 
			
		||||
    align-items: center;
 | 
			
		||||
    padding: 0 32px;
 | 
			
		||||
    height: 56px;
 | 
			
		||||
    white-space: nowrap;
 | 
			
		||||
    background: #5088FF;
 | 
			
		||||
    border-color: #5088FF;
 | 
			
		||||
    border-radius: 52px;
 | 
			
		||||
    position: relative;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    &:after {
 | 
			
		||||
      position: absolute;
 | 
			
		||||
      display: block;
 | 
			
		||||
      content: " ";
 | 
			
		||||
      bottom: -12px;
 | 
			
		||||
      left: 50%;
 | 
			
		||||
      transform: translateX(-50%);
 | 
			
		||||
      border: 12px solid transparent;
 | 
			
		||||
      border-bottom: none;
 | 
			
		||||
      height: 0;
 | 
			
		||||
      width: 0;
 | 
			
		||||
      border-top-color: inherit;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    &.offline {
 | 
			
		||||
      background: #C4CAD4;
 | 
			
		||||
      border-color: #C4CAD4;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    &.warning {
 | 
			
		||||
      background: #FFAA44;
 | 
			
		||||
      border-color: #FFAA44;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    &.abnormal {
 | 
			
		||||
      background: #F46159;
 | 
			
		||||
      border-color: #F46159;
 | 
			
		||||
 | 
			
		||||
      &:before {
 | 
			
		||||
        position: absolute;
 | 
			
		||||
        z-index: -1;
 | 
			
		||||
        bottom: -40px;
 | 
			
		||||
        width: 80px;
 | 
			
		||||
        height: 80px;
 | 
			
		||||
        border-radius: 50%;
 | 
			
		||||
        background-color: #F46159;
 | 
			
		||||
        transform: translate(-50%, -50%);
 | 
			
		||||
        animation: mapWarn 1s ease-out 0s infinite;
 | 
			
		||||
        content: " ";
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .AiMap {
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    height: 100%;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										65
									
								
								src/pages/guardianship/guardianship.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,65 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <section class="guardianship">
 | 
			
		||||
    <component ref="currentTab" :is="currentTab.comp"/>
 | 
			
		||||
    <ai-tabbar :active.sync="active" :list="bottomBar"/>
 | 
			
		||||
  </section>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import AiLoading from "../../components/AiLoading";
 | 
			
		||||
import GsLocation from "./gsLocation";
 | 
			
		||||
import AiTabbar from "../../components/AiTabbar";
 | 
			
		||||
import WardList from "./wardList";
 | 
			
		||||
import EarlyWarning from "./earlyWarning";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: "guardianship",
 | 
			
		||||
  components: {AiTabbar, AiLoading},
 | 
			
		||||
  provide() {
 | 
			
		||||
    return {
 | 
			
		||||
      top: this
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  computed: {
 | 
			
		||||
    bottomBar() {
 | 
			
		||||
      return [
 | 
			
		||||
        {text: "定位", iconPath: "bardwn", selectedIconPath: "bardwh", comp: GsLocation},
 | 
			
		||||
        {text: "人员", iconPath: "barryn", selectedIconPath: "barryh", comp: WardList},
 | 
			
		||||
        {text: "预警", iconPath: "baryjn", selectedIconPath: "baryjh", comp: EarlyWarning},
 | 
			
		||||
      ].map(e => ({
 | 
			
		||||
        ...e,
 | 
			
		||||
        iconPath: this.cdn(e.iconPath),
 | 
			
		||||
        selectedIconPath: this.cdn(e.selectedIconPath)
 | 
			
		||||
      }))
 | 
			
		||||
    },
 | 
			
		||||
    currentTab() {
 | 
			
		||||
      return this.bottomBar?.[this.active] || {}
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    cdn(icon) {
 | 
			
		||||
      return `${this.$cdn}guardianship/${icon}.png`
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  data() {
 | 
			
		||||
    return {
 | 
			
		||||
      active: 0
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  created() {
 | 
			
		||||
    this.$dict.load("intelligentGuardianshipItem", 'intelligentGuardianshipItem2', 'intelligentGuardianshipAbnormalStatus')
 | 
			
		||||
  },
 | 
			
		||||
  onReachBottom() {
 | 
			
		||||
    if (typeof this.$refs?.currentTab?.reachBottom == 'function') this.$refs?.currentTab.reachBottom()
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
.guardianship {
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  top: 0;
 | 
			
		||||
  bottom: 0;
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										75
									
								
								src/pages/guardianship/historyList.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,75 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <section class="historyList">
 | 
			
		||||
    <div flex>
 | 
			
		||||
      <b class="header" v-text="itemLabel"/>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div v-for="row in list" :key="row.id" flex class="spb row">
 | 
			
		||||
      <div :class="{abnormal:row.abnormalStatus==1}" v-text="row.itemValue"/>
 | 
			
		||||
      <span v-text="row.sampleTime"/>
 | 
			
		||||
    </div>
 | 
			
		||||
    <ai-back/>
 | 
			
		||||
  </section>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import AiBack from "../../components/AiBack";
 | 
			
		||||
export default {
 | 
			
		||||
  name: "historyList",
 | 
			
		||||
  components: {AiBack},
 | 
			
		||||
  computed: {
 | 
			
		||||
    itemLabel() {
 | 
			
		||||
      return '历史'+this.$dict.getLabel('intelligentGuardianshipItem', this.$route.query.type)+`(${this.$dict.getLabel('intelligentGuardianshipItemUnit',this.$route.query.type)})`
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  data() {
 | 
			
		||||
    return {
 | 
			
		||||
      list: []
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    getHistory() {
 | 
			
		||||
      let {type: item, id: deviceId} = this.$route.query
 | 
			
		||||
      this.$http.post("/app/appintelligentguardianshipdevice/queryMonitorList", null, {
 | 
			
		||||
        params: {deviceId, size: 999, item}
 | 
			
		||||
      }).then(res => {
 | 
			
		||||
        if (res?.data) {
 | 
			
		||||
          this.list = res.data.records
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  created() {
 | 
			
		||||
    this.$dict.load("intelligentGuardianshipItem",'intelligentGuardianshipItemUnit')
 | 
			
		||||
    this.getHistory()
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
.historyList {
 | 
			
		||||
  font-size: 30px;
 | 
			
		||||
 | 
			
		||||
  & > div {
 | 
			
		||||
    padding: 0 32px;
 | 
			
		||||
    border-bottom: 1px solid #ddd;
 | 
			
		||||
    height: 96px;
 | 
			
		||||
    background: #FFFFFF;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .header {
 | 
			
		||||
    font-size: 32px;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .row {
 | 
			
		||||
    color: #5AAD6A;
 | 
			
		||||
 | 
			
		||||
    .abnormal {
 | 
			
		||||
      color: #CD413A;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    & > span {
 | 
			
		||||
      color: #999;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										279
									
								
								src/pages/guardianship/userDetail.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,279 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <section class="userDetail">
 | 
			
		||||
    <div class="selectedInfo">
 | 
			
		||||
      <div class="header" flex>
 | 
			
		||||
        <img :src="`${$cdn}guardianship/tx.png`"/>
 | 
			
		||||
        <b v-text="detail.name"/>
 | 
			
		||||
        <div v-if="detail.abnormalStatus==1" class="abnormal">异常</div>
 | 
			
		||||
        <div class="fill"/>
 | 
			
		||||
        <make-calls :list="phoneList" :label="`<p>拨打电话</p>`"/>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="content">
 | 
			
		||||
        <ai-cell label="所属地区">{{ detail.areaName }}</ai-cell>
 | 
			
		||||
        <ai-cell label="联系电话">{{ detail.phone }}</ai-cell>
 | 
			
		||||
        <ai-cell label="性别">{{ $dict.getLabel('sex', detail.sex) }}</ai-cell>
 | 
			
		||||
        <ai-cell label="年龄">{{ $calcAge(detail.idNumber) }}</ai-cell>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="card">
 | 
			
		||||
      <div flex class="spb header">
 | 
			
		||||
        <b v-text="`设备状况`"/>
 | 
			
		||||
        <span class="onlineStatus" v-html="detail.onlineStatus==1?'设备在线':'<p>设备离线</p>'"/>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div flex class="spb wrap quotas">
 | 
			
		||||
        <div class="quota" v-for="(op,i) in quotas" :key="i" flex @tap="handleShowHistory(op)">
 | 
			
		||||
          <img :src="op.icon"/>
 | 
			
		||||
          <div class="fill" v-text="op.label"/>
 | 
			
		||||
          <div :class="{abnormal:op.abnormal}" v-text="op.value"/>
 | 
			
		||||
          <u-icon name="arrow-right" color="#ddd"/>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="navigation">
 | 
			
		||||
        <div class="content spb" flex>
 | 
			
		||||
          <div flex class="spb wrap">
 | 
			
		||||
            <div class="fill" v-text="detail.gpsDesc"/>
 | 
			
		||||
            <span>最后更新:{{ detail.lastUpdateTime }}</span>
 | 
			
		||||
            <div class="battery" flex>
 | 
			
		||||
              <img :src="batteryIcon"/>
 | 
			
		||||
              <div v-text="`剩余${detail.electricQuantity||0}%`"/>
 | 
			
		||||
            </div>
 | 
			
		||||
          </div>
 | 
			
		||||
          <open-map :data="detail"/>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="card">
 | 
			
		||||
      <div flex class="spb header">
 | 
			
		||||
        <b v-text="`监护人信息`"/>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div flex class="spb guardian" v-for="row in detail.guardians" :key="row.id">
 | 
			
		||||
        <span v-text="row.guardianName"/>
 | 
			
		||||
        <div v-text="row.guardianPhone"/>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <ai-back/>
 | 
			
		||||
  </section>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import MakeCalls from "./component/makeCalls";
 | 
			
		||||
import OpenMap from "./component/openMap";
 | 
			
		||||
import AiCell from "../../components/AiCell";
 | 
			
		||||
import AiBack from "../../components/AiBack";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: "userDetail",
 | 
			
		||||
  components: {AiBack, AiCell, OpenMap, MakeCalls},
 | 
			
		||||
  computed: {
 | 
			
		||||
    batteryIcon() {
 | 
			
		||||
      return this.cdn(this.detail.electricQuantity == 100 ? 'dcm' : 'dcq')
 | 
			
		||||
    },
 | 
			
		||||
    quotas() {
 | 
			
		||||
      let quota = [
 | 
			
		||||
        {key: "0", icon: "1"},
 | 
			
		||||
        {key: "1", icon: "2"},
 | 
			
		||||
        {key: "2", icon: "3"},
 | 
			
		||||
        {key: "3", icon: "4"},
 | 
			
		||||
      ]
 | 
			
		||||
      return quota.map(e => {
 | 
			
		||||
        let item = this.detail.quota?.find(d => d.item == e.key)
 | 
			
		||||
        let label = this.$dict.getLabel('intelligentGuardianshipItem', e.key)
 | 
			
		||||
        return {
 | 
			
		||||
          label, icon: this.cdn(e.icon), type: e.key,
 | 
			
		||||
          value: item?.itemValue || "-",
 | 
			
		||||
          abnormal: item?.abnormalStatus == 1
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
    phoneList() {
 | 
			
		||||
      let {name: guardianName, phone: guardianPhone} = this.detail
 | 
			
		||||
      return [{guardianName, guardianPhone}, ...this.detail.guardians]
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  data() {
 | 
			
		||||
    return {
 | 
			
		||||
      detail: {
 | 
			
		||||
        guardians: []
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    cdn(icon) {
 | 
			
		||||
      return `${this.$cdn}guardianship/${icon}.png`
 | 
			
		||||
    },
 | 
			
		||||
    getDetail(deviceId) {
 | 
			
		||||
      this.$http.post("/app/appintelligentguardianshipdevice/queryMonitorList", null, {
 | 
			
		||||
        params: {type: 1, deviceId}
 | 
			
		||||
      }).then(res => {
 | 
			
		||||
        if (res?.data) {
 | 
			
		||||
          this.$set(this.detail, 'quota', res.data.records)
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
      this.$http.post("/app/appintelligentguardianshipdevice/queryDetailById", null, {
 | 
			
		||||
        params: {id: deviceId}
 | 
			
		||||
      }).then(res => {
 | 
			
		||||
        if (res?.data) {
 | 
			
		||||
          this.detail = {...this.detail, ...res.data}
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
    handleShowHistory(item) {
 | 
			
		||||
      uni.navigateTo({url: `./historyList?type=${item.type}&id=${this.$route.query.id}`})
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  created() {
 | 
			
		||||
    this.$dict.load("intelligentGuardianshipItem", 'sex')
 | 
			
		||||
    this.getDetail(this.$route.query.id)
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
.userDetail {
 | 
			
		||||
  padding-bottom: 60px;
 | 
			
		||||
 | 
			
		||||
  & > * {
 | 
			
		||||
    margin-bottom: 16px;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .card {
 | 
			
		||||
    background: #fff;
 | 
			
		||||
    font-size: 32px;
 | 
			
		||||
    box-shadow: 0 1px 1px 0 rgba(221, 221, 221, 1);
 | 
			
		||||
 | 
			
		||||
    .header {
 | 
			
		||||
      height: 96px;
 | 
			
		||||
      background: #FFFFFF;
 | 
			
		||||
      border-bottom: 1px solid #ddd;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    & > .spb {
 | 
			
		||||
      padding: 0 32px;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ::v-deep .selectedInfo {
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    background: #fff;
 | 
			
		||||
    overflow: hidden;
 | 
			
		||||
    box-sizing: border-box;
 | 
			
		||||
 | 
			
		||||
    .header {
 | 
			
		||||
      height: 136px;
 | 
			
		||||
      font-size: 40px;
 | 
			
		||||
      padding: 0 32px;
 | 
			
		||||
      border-bottom: 1px solid #D8DDE6;
 | 
			
		||||
 | 
			
		||||
      & > img {
 | 
			
		||||
        width: 82px;
 | 
			
		||||
        height: 82px;
 | 
			
		||||
        margin-right: 16px;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .abnormal {
 | 
			
		||||
        color: #FF4466;
 | 
			
		||||
        font-size: 24px;
 | 
			
		||||
        padding: 12px;
 | 
			
		||||
        background: rgba(#EC4461, .1);
 | 
			
		||||
        border-radius: 8px;
 | 
			
		||||
        margin-left: 16px;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      span {
 | 
			
		||||
        margin-left: 0;
 | 
			
		||||
        color: #999;
 | 
			
		||||
        font-size: 20px;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    & > .content {
 | 
			
		||||
      padding: 32px;
 | 
			
		||||
      font-size: 30px;
 | 
			
		||||
 | 
			
		||||
      ::v-deep .AiCell {
 | 
			
		||||
        padding: 0;
 | 
			
		||||
        min-height: 58px;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .quotas {
 | 
			
		||||
    margin-top: 24px;
 | 
			
		||||
 | 
			
		||||
    .quota {
 | 
			
		||||
      cursor: pointer;
 | 
			
		||||
      width: 318px;
 | 
			
		||||
      height: 84px;
 | 
			
		||||
      background: #F4F5F6;
 | 
			
		||||
      border-radius: 8px;
 | 
			
		||||
      padding: 0 8px 0 24px;
 | 
			
		||||
      box-sizing: border-box;
 | 
			
		||||
      margin-bottom: 36px;
 | 
			
		||||
      font-size: 28px;
 | 
			
		||||
 | 
			
		||||
      img {
 | 
			
		||||
        margin-right: 16px;
 | 
			
		||||
        width: 56px;
 | 
			
		||||
        height: 56px;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .abnormal {
 | 
			
		||||
        color: #FF4466;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  .navigation {
 | 
			
		||||
    .content {
 | 
			
		||||
      padding: 10px 40px 32px;
 | 
			
		||||
      font-size: 26px;
 | 
			
		||||
 | 
			
		||||
      & > .spb {
 | 
			
		||||
        margin-right: 40px;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .fill {
 | 
			
		||||
        min-width: 100%;
 | 
			
		||||
        flex-shrink: 0;
 | 
			
		||||
        margin-bottom: 10px;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      span {
 | 
			
		||||
        margin-left: 0;
 | 
			
		||||
        color: #999;
 | 
			
		||||
        font-size: 22px;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .battery > img {
 | 
			
		||||
        margin-left: 32px;
 | 
			
		||||
        margin-right: 14px;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ::v-deep .onlineStatus {
 | 
			
		||||
    font-size: 30px;
 | 
			
		||||
    color: #5AAD6A;
 | 
			
		||||
 | 
			
		||||
    p {
 | 
			
		||||
      color: #F5A319;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .guardian {
 | 
			
		||||
    height: 96px;
 | 
			
		||||
    border-bottom: 1px solid #ddd;
 | 
			
		||||
    font-size: 28px;
 | 
			
		||||
    color: #222;
 | 
			
		||||
 | 
			
		||||
    &:last-of-type {
 | 
			
		||||
      border-bottom: none;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    span {
 | 
			
		||||
      color: #666666;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										106
									
								
								src/pages/guardianship/wardList.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,106 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <section class="wardList">
 | 
			
		||||
    <ai-top-fixed>
 | 
			
		||||
      <u-search v-model="search" placeholder="请输入姓名" :show-action="false"
 | 
			
		||||
                search-icon-color="#ccc" placeholder-color="#999"
 | 
			
		||||
                @change="page.current=1,getUser()"/>
 | 
			
		||||
      <area-selector :areaId="areaId" @select="handleSelectArea"/>
 | 
			
		||||
    </ai-top-fixed>
 | 
			
		||||
    <div class="userList">
 | 
			
		||||
      <div v-for="row in list" :key="row.id" flex class="row" @tap="handleShowDetail(row)">
 | 
			
		||||
        <img :src="top.cdn(row.onlineStatus==1?'zxtx':'lxtx')"/>
 | 
			
		||||
        <b class="fill" v-text="row.name"/>
 | 
			
		||||
        <div class="status" :style="{color:$dict.getColor('intelligentGuardianshipAbnormalStatus',row.abnormalStatus)}"
 | 
			
		||||
             v-text="$dict.getLabel('intelligentGuardianshipAbnormalStatus',row.abnormalStatus)"/>
 | 
			
		||||
        <u-icon name="arrow-right" color="#ddd"/>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
  </section>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import AiTopFixed from "../../components/AiTopFixed";
 | 
			
		||||
import {mapState} from "vuex";
 | 
			
		||||
import AreaSelector from "./component/areaSelector";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: "wardList",
 | 
			
		||||
  components: {AreaSelector, AiTopFixed},
 | 
			
		||||
  computed: {
 | 
			
		||||
    ...mapState(['user']),
 | 
			
		||||
  },
 | 
			
		||||
  inject: ['top'],
 | 
			
		||||
  data() {
 | 
			
		||||
    return {
 | 
			
		||||
      search: "",
 | 
			
		||||
      areaId: "",
 | 
			
		||||
      page: {current: 1, size: 20, total: 0},
 | 
			
		||||
      list: []
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    getUser() {
 | 
			
		||||
      let {areaId, search: name} = this
 | 
			
		||||
      this.$http.post("/app/appintelligentguardianshipdevice/list", null, {
 | 
			
		||||
        params: {areaId, name, ...this.page}
 | 
			
		||||
      }).then(res => {
 | 
			
		||||
        if (res?.data) {
 | 
			
		||||
          let data = res.data.records.reverse()
 | 
			
		||||
          if (this.page.current > 1) {
 | 
			
		||||
            this.list = [...this.list, ...data]
 | 
			
		||||
          } else this.list = data
 | 
			
		||||
          this.page.total = res.data.total
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
    handleSelectArea({id}) {
 | 
			
		||||
      this.areaId = id
 | 
			
		||||
      this.getUser()
 | 
			
		||||
    },
 | 
			
		||||
    reachBottom() {
 | 
			
		||||
      if (this.page.total > this.list.length) {
 | 
			
		||||
        this.page.current++
 | 
			
		||||
        this.getUser()
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    handleShowDetail(user) {
 | 
			
		||||
      uni.navigateTo({url: `./userDetail?id=${user.id}`})
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  created() {
 | 
			
		||||
    this.areaId = JSON.parse(JSON.stringify(this.user.areaId))
 | 
			
		||||
    this.getUser()
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
.wardList {
 | 
			
		||||
  background: #f5f5f5;
 | 
			
		||||
  padding-bottom: 130px;
 | 
			
		||||
  font-size: 30px;
 | 
			
		||||
 | 
			
		||||
  ::v-deep .userList {
 | 
			
		||||
    margin-top: 16px;
 | 
			
		||||
    background: #fff;
 | 
			
		||||
 | 
			
		||||
    .row {
 | 
			
		||||
      font-size: 36px;
 | 
			
		||||
      margin-left: 32px;
 | 
			
		||||
      padding-right: 32px;
 | 
			
		||||
      height: 104px;
 | 
			
		||||
      border-bottom: 1px solid #ddd;
 | 
			
		||||
 | 
			
		||||
      img {
 | 
			
		||||
        width: 72px;
 | 
			
		||||
        height: 72px;
 | 
			
		||||
        margin-right: 38px;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .status {
 | 
			
		||||
        margin-right: 12px;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										185
									
								
								src/pages/guardianship/warningDetail.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,185 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <section class="warningDetail">
 | 
			
		||||
    <div flex class="header">
 | 
			
		||||
      <b v-text="detail.name"/>
 | 
			
		||||
      <div>
 | 
			
		||||
        {{ $dict.getLabel('intelligentGuardianshipItem2', detail.item) }}
 | 
			
		||||
        {{ detail.itemValue }}
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <ai-map class="fill" :map.sync="amap" :lib.sync="mapLib"/>
 | 
			
		||||
    <div class="navigation">
 | 
			
		||||
      <div class="content spb" flex>
 | 
			
		||||
        <div flex class="spb wrap">
 | 
			
		||||
          <div class="fill" v-text="detail.gpsDesc"/>
 | 
			
		||||
          <span>最后更新:{{ detail.createTime }}</span>
 | 
			
		||||
        </div>
 | 
			
		||||
        <open-map :data="detail"/>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <make-calls :list="phoneList">
 | 
			
		||||
      <div class="bottomBtn">拨打电话</div>
 | 
			
		||||
    </make-calls>
 | 
			
		||||
    <ai-back/>
 | 
			
		||||
  </section>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import OpenMap from "./component/openMap";
 | 
			
		||||
import MakeCalls from "./component/makeCalls";
 | 
			
		||||
import AiBack from "../../components/AiBack";
 | 
			
		||||
import AiMap from "../../components/AiMap";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: "warningDetail",
 | 
			
		||||
  components: {AiMap, AiBack, MakeCalls, OpenMap},
 | 
			
		||||
  computed: {
 | 
			
		||||
    phoneList() {
 | 
			
		||||
      let {name: guardianName, phone: guardianPhone} = this.detail
 | 
			
		||||
      return [{guardianName, guardianPhone}, ...this.detail.guardians]
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  data() {
 | 
			
		||||
    return {
 | 
			
		||||
      detail: {guardians: []},
 | 
			
		||||
      mapLib: null,
 | 
			
		||||
      amap: null,
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    getDetail(id) {
 | 
			
		||||
      return this.$http.post("/app/appintelligentguardianshipalarm/queryDetailById", null, {
 | 
			
		||||
        params: {id},
 | 
			
		||||
        withoutToken: true
 | 
			
		||||
      }).then(res => {
 | 
			
		||||
        if (res?.data) {
 | 
			
		||||
          this.detail = res.data
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
    initMap() {
 | 
			
		||||
      if (this.mapLib) {
 | 
			
		||||
        let pos = new this.mapLib.LngLat(this.detail.lng, this.detail.lat)
 | 
			
		||||
        this.amap.add(new this.mapLib.Marker({
 | 
			
		||||
          position: pos,
 | 
			
		||||
          anchor: 'bottom-center',
 | 
			
		||||
          content: `<div class="marker">${this.detail.name}</div>`,
 | 
			
		||||
        }))
 | 
			
		||||
        this.amap.setFitView()
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  watch: {
 | 
			
		||||
    mapLib(v) {
 | 
			
		||||
      this.detail.id && v && this.initMap()
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  created() {
 | 
			
		||||
    this.$dict.load("intelligentGuardianshipItem",'intelligentGuardianshipItem2', 'sex')
 | 
			
		||||
  },
 | 
			
		||||
  mounted() {
 | 
			
		||||
    this.getDetail(this.$route.query.id).then(() => this.initMap())
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
.warningDetail {
 | 
			
		||||
  padding: 48px 48px 112px;
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  height: 100%;
 | 
			
		||||
  box-sizing: border-box;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-direction: column;
 | 
			
		||||
  position: absolute;
 | 
			
		||||
 | 
			
		||||
  .header {
 | 
			
		||||
    font-size: 40px;
 | 
			
		||||
    font-weight: bold;
 | 
			
		||||
    color: #333333;
 | 
			
		||||
    justify-content: center;
 | 
			
		||||
    margin-bottom: 48px;
 | 
			
		||||
 | 
			
		||||
    & > div {
 | 
			
		||||
      color: #EC4461;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .navigation {
 | 
			
		||||
    .content {
 | 
			
		||||
      padding: 10px 0 32px;
 | 
			
		||||
      font-size: 28px;
 | 
			
		||||
      color: #555;
 | 
			
		||||
 | 
			
		||||
      & > .spb {
 | 
			
		||||
        margin-right: 40px;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .fill {
 | 
			
		||||
        min-width: 100%;
 | 
			
		||||
        flex-shrink: 0;
 | 
			
		||||
        margin-bottom: 10px;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      span {
 | 
			
		||||
        margin-left: 0;
 | 
			
		||||
        color: #999;
 | 
			
		||||
        font-size: 22px;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .bottomBtn {
 | 
			
		||||
    position: fixed;
 | 
			
		||||
    left: 0;
 | 
			
		||||
    bottom: 0;
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    text-align: center;
 | 
			
		||||
    color: #fff;
 | 
			
		||||
    background: #1365DD;
 | 
			
		||||
    line-height: 112px;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .AiMap {
 | 
			
		||||
    margin-bottom: 72px;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  ::v-deep .marker {
 | 
			
		||||
    border-radius: 52px;
 | 
			
		||||
    background: #F46159;
 | 
			
		||||
    color: #fff;
 | 
			
		||||
    font-size: 22px;
 | 
			
		||||
    padding: 4px 16px;
 | 
			
		||||
    white-space: nowrap;
 | 
			
		||||
    position: relative;
 | 
			
		||||
 | 
			
		||||
    &:before {
 | 
			
		||||
      position: absolute;
 | 
			
		||||
      left: calc(50% - 30px);
 | 
			
		||||
      bottom: -34px;
 | 
			
		||||
      z-index: -1;
 | 
			
		||||
      width: 60px;
 | 
			
		||||
      height: 60px;
 | 
			
		||||
      border-radius: 50%;
 | 
			
		||||
      background-color: #F46159;
 | 
			
		||||
      animation: mapWarn 1s ease-out 0s infinite;
 | 
			
		||||
      content: " ";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    &:after {
 | 
			
		||||
      position: absolute;
 | 
			
		||||
      display: block;
 | 
			
		||||
      content: " ";
 | 
			
		||||
      bottom: -8px;
 | 
			
		||||
      left: 50%;
 | 
			
		||||
      transform: translateX(-50%);
 | 
			
		||||
      border: 8px solid transparent;
 | 
			
		||||
      border-bottom: none;
 | 
			
		||||
      border-top-color: #F46159;
 | 
			
		||||
      height: 0;
 | 
			
		||||
      width: 0;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										184
									
								
								src/pages/interview/detail.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,184 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="interviewDetail">
 | 
			
		||||
    <template v-if="isEdit">
 | 
			
		||||
      <u-form ref="interviewForm" label-position="top" :rules="rules" :model="form">
 | 
			
		||||
        <u-form-item label="调查走访事项" prop="title" required>
 | 
			
		||||
          <u-input v-model="form.title" placeholder="请输入,最多30字" maxlength="30"/>
 | 
			
		||||
        </u-form-item>
 | 
			
		||||
        <u-form-item label="调查走访内容" prop="content">
 | 
			
		||||
          <ai-textarea v-model="form.content" placeholder="请输入,最多500字" :maxlength="500"/>
 | 
			
		||||
        </u-form-item>
 | 
			
		||||
        <u-form-item label="图片(最多9张)">
 | 
			
		||||
          <ai-uploader multiple :limit="9" :def.sync="form.fileList" action="/admin/file/add2"/>
 | 
			
		||||
        </u-form-item>
 | 
			
		||||
      </u-form>
 | 
			
		||||
      <div bottom>
 | 
			
		||||
        <u-button type="primary" @tap="submitForm">保存</u-button>
 | 
			
		||||
      </div>
 | 
			
		||||
    </template>
 | 
			
		||||
    <template v-else>
 | 
			
		||||
      <div class="headerPane">
 | 
			
		||||
        <b>{{ form.title }}</b>
 | 
			
		||||
        <div>记录时间:{{ form.createTime }}</div>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="contentPane">
 | 
			
		||||
        <div v-html="form.content"/>
 | 
			
		||||
        <div flex class="wrap">
 | 
			
		||||
          <ai-image v-for="(op,i) in form.fileList" :src="op.accessUrl" preview :key="i"/>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </template>
 | 
			
		||||
    <ai-back/>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import UButton from "../../uview/components/u-button/u-button";
 | 
			
		||||
import AiUploader from "../../components/AiUploader";
 | 
			
		||||
import UInput from "../../uview/components/u-input/u-input";
 | 
			
		||||
import AiImage from "../../components/AiImage";
 | 
			
		||||
import AiTextarea from "../../components/AiTextarea";
 | 
			
		||||
import UFormItem from "../../uview/components/u-form-item/u-form-item";
 | 
			
		||||
import AiBack from "../../components/AiBack";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: 'interviewDetail',
 | 
			
		||||
  components: {AiBack, UFormItem, AiTextarea, AiImage, UInput, AiUploader, UButton},
 | 
			
		||||
  computed: {
 | 
			
		||||
    isEdit() {
 | 
			
		||||
      let flag = this.$route.query?.detail != 1
 | 
			
		||||
      !flag && uni.setNavigationBarTitle({title: "走访详情"})
 | 
			
		||||
      return flag
 | 
			
		||||
    },
 | 
			
		||||
    rules() {
 | 
			
		||||
      return {
 | 
			
		||||
        title: [{required: true, message: '请输入 调查走访事项'}],
 | 
			
		||||
        // content: [{required: true, message: '请输入 调查走访内容'}],
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  data() {
 | 
			
		||||
    return {
 | 
			
		||||
      form: {
 | 
			
		||||
        fileList: []
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  created() {
 | 
			
		||||
    this.searchDetail();
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    submitForm() {
 | 
			
		||||
      this.$refs.interviewForm?.validate(v => {
 | 
			
		||||
        if (v) {
 | 
			
		||||
          this.$http.post(`/app/appinterview/add-xcx`, {
 | 
			
		||||
            ...this.form
 | 
			
		||||
          }).then(res => {
 | 
			
		||||
            if (res?.code == 0) {
 | 
			
		||||
              this.$u.toast("提交成功!")
 | 
			
		||||
              uni.navigateBack()
 | 
			
		||||
            }
 | 
			
		||||
          })
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
    searchDetail() {
 | 
			
		||||
      let {id} = this.$route.query
 | 
			
		||||
      id && this.$http.post(`/app/appinterview/queryDetailById`, null, {
 | 
			
		||||
        params: {id}
 | 
			
		||||
      }).then(res => {
 | 
			
		||||
        if (res?.data) {
 | 
			
		||||
          this.form = {...res.data};
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
.interviewDetail {
 | 
			
		||||
  background: #F3F6F9;
 | 
			
		||||
  min-height: 100%;
 | 
			
		||||
 | 
			
		||||
  .u-form {
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    height: 100%;
 | 
			
		||||
    overflow-y: auto;
 | 
			
		||||
    background-color: #f3f6f9;
 | 
			
		||||
    position: relative;
 | 
			
		||||
    padding: 0 0 188px;
 | 
			
		||||
    box-sizing: border-box;
 | 
			
		||||
    font-size: 30px;
 | 
			
		||||
 | 
			
		||||
    ::v-deep textarea {
 | 
			
		||||
      width: 100%;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ::v-deep .u-form-item {
 | 
			
		||||
      margin-bottom: 16px;
 | 
			
		||||
 | 
			
		||||
      .u-form-item--left__content__label {
 | 
			
		||||
        font-weight: 400;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      div[flex] {
 | 
			
		||||
        width: 100%;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  div[bottom] {
 | 
			
		||||
    z-index: 99;
 | 
			
		||||
    padding: 0;
 | 
			
		||||
    height: 112px;
 | 
			
		||||
 | 
			
		||||
    .u-btn {
 | 
			
		||||
      height: 100%;
 | 
			
		||||
      border-radius: 0;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ::v-deep .headerPane {
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    background: #3975C6;
 | 
			
		||||
    color: #fff;
 | 
			
		||||
    padding: 24px 32px 32px;
 | 
			
		||||
    box-sizing: border-box;
 | 
			
		||||
    font-size: 28px;
 | 
			
		||||
 | 
			
		||||
    b {
 | 
			
		||||
      display: block;
 | 
			
		||||
      font-size: 40px;
 | 
			
		||||
      line-height: 64px;
 | 
			
		||||
      letter-spacing: 2px;
 | 
			
		||||
      margin-bottom: 16px;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ::v-deep .contentPane {
 | 
			
		||||
    padding: 32px;
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    box-sizing: border-box;
 | 
			
		||||
    font-size: 32px;
 | 
			
		||||
    font-weight: 400;
 | 
			
		||||
    color: #666;
 | 
			
		||||
    line-height: 56px;
 | 
			
		||||
 | 
			
		||||
    .wrap {
 | 
			
		||||
      margin-top: 32px;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .AiImage {
 | 
			
		||||
      width: 31%;
 | 
			
		||||
      margin-bottom: 16px;
 | 
			
		||||
      margin-right: 16px;
 | 
			
		||||
 | 
			
		||||
      image {
 | 
			
		||||
        width: 100%;
 | 
			
		||||
        height: 218px;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										224
									
								
								src/pages/interview/interview.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,224 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="interview">
 | 
			
		||||
    <ai-top-fixed>
 | 
			
		||||
      <div flex>
 | 
			
		||||
        <ai-date placeholder="日期选择" mode="range" @change="handleDateSearch"/>
 | 
			
		||||
        <u-search placeholder="请输入标题" :show-action="false" v-model="search.title" @search="current=1,getList()"/>
 | 
			
		||||
      </div>
 | 
			
		||||
    </ai-top-fixed>
 | 
			
		||||
    <template v-if="list.length>0">
 | 
			
		||||
      <ai-card v-for="(e,index) in list" :key="index" @click.native="goDetail(e.id,1)">
 | 
			
		||||
        <template #custom>
 | 
			
		||||
          <div flex>
 | 
			
		||||
            <b class="fill">{{ e.title }}</b>
 | 
			
		||||
          </div>
 | 
			
		||||
          <div flex v-if="!!e.fileList" class="wrap">
 | 
			
		||||
            <ai-image v-for="(op,i) in e.fileList.slice(0,3)" :src="op.accessUrl" preview :key="i"/>
 | 
			
		||||
          </div>
 | 
			
		||||
          <div class="bottom">{{ e.createTime }}</div>
 | 
			
		||||
        </template>
 | 
			
		||||
        <template #menu>
 | 
			
		||||
          <div class="menu" @tap.stop="goDetail(e.id)">编辑</div>
 | 
			
		||||
          <div class="menu" @tap.stop="handleDelete(e.id)">删除</div>
 | 
			
		||||
        </template>
 | 
			
		||||
      </ai-card>
 | 
			
		||||
      <u-loadmore :status="loadmore" color="#999" font-size="24"
 | 
			
		||||
                  margin-top="32" margin-bottom="80"/>
 | 
			
		||||
    </template>
 | 
			
		||||
    <div class="no-message" v-else>
 | 
			
		||||
      <image src="https://cdn.cunwuyun.cn/wxAdmin/img/message.png"/>
 | 
			
		||||
      <p>您还未添加过入户调查走访<br>点击<b>新增按钮</b>试试吧~</p>
 | 
			
		||||
    </div>
 | 
			
		||||
    <ai-fixed-btn>
 | 
			
		||||
      <div class="addBtn iconfont iconfont-iconfangda" @tap="gotoAdd()"/>
 | 
			
		||||
    </ai-fixed-btn>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import AiSelect from "../../components/AiSelect";
 | 
			
		||||
import AiTopFixed from "../../components/AiTopFixed";
 | 
			
		||||
import AiCard from "../../components/AiCard";
 | 
			
		||||
import AiImage from "../../components/AiImage";
 | 
			
		||||
import AiDate from "../../components/AiDate";
 | 
			
		||||
import AiFixedBtn from "../../components/AiFixedBtn";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: "interview",
 | 
			
		||||
  components: {AiFixedBtn, AiDate, AiImage, AiCard, AiTopFixed, AiSelect},
 | 
			
		||||
  data() {
 | 
			
		||||
    return {
 | 
			
		||||
      search: {title: ""},
 | 
			
		||||
      list: [],
 | 
			
		||||
      current: 1,
 | 
			
		||||
      pages: 0
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  computed: {
 | 
			
		||||
    loadmore() {
 | 
			
		||||
      return this.pages <= this.current ? 'loading ' : 'nomore'
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  onShow() {
 | 
			
		||||
    this.current = 1;
 | 
			
		||||
    this.getList()
 | 
			
		||||
  },
 | 
			
		||||
  onReachBottom() {
 | 
			
		||||
    this.current++;
 | 
			
		||||
    this.getList()
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    getList() {
 | 
			
		||||
      this.$http.post('/app/appinterview/list-xcx', null, {
 | 
			
		||||
        params: {
 | 
			
		||||
          current: this.current,
 | 
			
		||||
          size: 10,
 | 
			
		||||
          ...this.search
 | 
			
		||||
        }
 | 
			
		||||
      }).then(res => {
 | 
			
		||||
        if (res?.data) {
 | 
			
		||||
          this.list = this.current > 1 ? [...this.list, ...res.data.records] : res.data.records
 | 
			
		||||
          this.pages = res.data.pages
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
    goDetail(id, readonly) {
 | 
			
		||||
      let url = `./detail?id=${id}`
 | 
			
		||||
      readonly && (url += "&detail=1")
 | 
			
		||||
      uni.navigateTo({url})
 | 
			
		||||
    },
 | 
			
		||||
    gotoAdd() {
 | 
			
		||||
      uni.navigateTo({url: `./detail`})
 | 
			
		||||
    },
 | 
			
		||||
    handleDelete(ids) {
 | 
			
		||||
      this.$confirm("是否要删除该调查走访").then(() => {
 | 
			
		||||
        this.$http.post("/app/appinterview/delete", null, {
 | 
			
		||||
          params: {ids}
 | 
			
		||||
        }).then(res => {
 | 
			
		||||
          if (res?.code == 0) {
 | 
			
		||||
            this.$u.toast("删除成功!")
 | 
			
		||||
            this.getList()
 | 
			
		||||
          }
 | 
			
		||||
        })
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
    handleDateSearch(v) {
 | 
			
		||||
      this.search.startTime = v.startDate
 | 
			
		||||
      this.search.endTime = v.endDate || v.startDate
 | 
			
		||||
      this.current = 1
 | 
			
		||||
      this.getList()
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
.interview {
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  min-height: 100%;
 | 
			
		||||
  box-sizing: border-box;
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  background: #fff;
 | 
			
		||||
 | 
			
		||||
  .no-message {
 | 
			
		||||
    margin-top: 140px;
 | 
			
		||||
    text-align: center;
 | 
			
		||||
    color: #888;
 | 
			
		||||
    font-size: 30px;
 | 
			
		||||
 | 
			
		||||
    b {
 | 
			
		||||
      font-size: 32px;
 | 
			
		||||
      color: $uni-color-primary;
 | 
			
		||||
      padding: 0 8px;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    image {
 | 
			
		||||
      width: 320px;
 | 
			
		||||
      height: 240px;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ::v-deep .AiCard {
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    min-height: 160px;
 | 
			
		||||
    background: #FFFFFF;
 | 
			
		||||
    padding: 32px 32px 0;
 | 
			
		||||
    box-sizing: border-box;
 | 
			
		||||
    display: flex;
 | 
			
		||||
    flex-direction: column;
 | 
			
		||||
    position: relative;
 | 
			
		||||
 | 
			
		||||
    b {
 | 
			
		||||
      display: block;
 | 
			
		||||
      width: 100%;
 | 
			
		||||
      font-size: 30px;
 | 
			
		||||
      white-space: nowrap;
 | 
			
		||||
      overflow: hidden;
 | 
			
		||||
      text-overflow: ellipsis;
 | 
			
		||||
      color: #333;
 | 
			
		||||
      margin-right: 60px;
 | 
			
		||||
      margin-bottom: 20px;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .iconfont-iconMore {
 | 
			
		||||
      color: #666;
 | 
			
		||||
      position: absolute;
 | 
			
		||||
      right: 32px;
 | 
			
		||||
      top: 32px;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .bottom {
 | 
			
		||||
      font-size: 24px;
 | 
			
		||||
      color: #999999;
 | 
			
		||||
      padding: 24px 0;
 | 
			
		||||
      border-bottom: 1px solid rgba(221, 221, 221, .4);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .AiImage {
 | 
			
		||||
      width: 30%;
 | 
			
		||||
      margin-bottom: 8px;
 | 
			
		||||
      margin-right: 8px;
 | 
			
		||||
 | 
			
		||||
      image {
 | 
			
		||||
        width: 100%;
 | 
			
		||||
        height: 218px;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .addBtn {
 | 
			
		||||
    width: 96px;
 | 
			
		||||
    height: 96px;
 | 
			
		||||
    flex-shrink: 0;
 | 
			
		||||
    background: $uni-color-primary;
 | 
			
		||||
    box-shadow: 0 8px 16px 0 rgba(0, 0, 0, 0.2);
 | 
			
		||||
    font-size: 48px;
 | 
			
		||||
    color: #fff;
 | 
			
		||||
    border-radius: 50%;
 | 
			
		||||
    justify-content: center;
 | 
			
		||||
    align-items: center;
 | 
			
		||||
    display: flex;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .menu {
 | 
			
		||||
    text-align: center;
 | 
			
		||||
    line-height: 80px;
 | 
			
		||||
    width: 192px;
 | 
			
		||||
    height: 80px;
 | 
			
		||||
    font-size: 28px;
 | 
			
		||||
    font-weight: 400;
 | 
			
		||||
    color: #333333;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ::v-deep .u-search {
 | 
			
		||||
    margin-bottom: 0 !important;
 | 
			
		||||
    padding-left: 146px;
 | 
			
		||||
    box-shadow: none;
 | 
			
		||||
 | 
			
		||||
    .u-content {
 | 
			
		||||
      padding-left: 50px;
 | 
			
		||||
      box-sizing: border-box;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										174
									
								
								src/pages/loading.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,174 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <section class="loading">
 | 
			
		||||
    <!--    <div class="iconfont iconfont-iconWeChat"/>-->
 | 
			
		||||
    <!--    <div class="iconfont iconfont-iconjuminxinxi"/>-->
 | 
			
		||||
    <!--    <div class="iconfont iconfont-iconLogo"/>-->
 | 
			
		||||
    <ai-result v-if="result.tips" v-bind="result"/>
 | 
			
		||||
    <template v-if="isDev">
 | 
			
		||||
      <input v-if="!!$route.query.code" class="codeText" :value="$route.query.code"/>
 | 
			
		||||
      <div class="codeBtn" @click="devGetCode">获取code</div>
 | 
			
		||||
      <div flex class="appsPane wrap">
 | 
			
		||||
        <b v-for="app in apps" :key="app.key" @tap="gotoApp(app.key)">{{ app.name }}</b>
 | 
			
		||||
      </div>
 | 
			
		||||
    </template>
 | 
			
		||||
 | 
			
		||||
  </section>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import {mapActions, mapState} from 'vuex'
 | 
			
		||||
import AiResult from "../components/AiResult";
 | 
			
		||||
import UTag from "../uview/components/u-tag/u-tag";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: 'loading',
 | 
			
		||||
  components: {UTag, AiResult},
 | 
			
		||||
  inject: ['root'],
 | 
			
		||||
  computed: {
 | 
			
		||||
    ...mapState(['token', 'apps', 'openUser', 'user']),
 | 
			
		||||
    currentApp() {
 | 
			
		||||
      return this.apps.find(e => e.key == this.$route.query.app) || {}
 | 
			
		||||
    },
 | 
			
		||||
    isDev() {
 | 
			
		||||
      return this.$route.hash == "#dev"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  data() {
 | 
			
		||||
    return {
 | 
			
		||||
      result: {}
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    ...mapActions(['getToken', 'getAccount', 'agentSign', 'getUserInfo', 'getCode', 'closeAgent']),
 | 
			
		||||
    initAccess() {
 | 
			
		||||
      if (this.$route.hash == "#error" || this.isDev) {
 | 
			
		||||
        return Promise.resolve()
 | 
			
		||||
      } else if (this.$route.hash == "#form") {
 | 
			
		||||
        if (this.openUser?.openId || !!this.$route.query.preview) {
 | 
			
		||||
          this.openForm()
 | 
			
		||||
        } else if (this.$route.query?.code) {
 | 
			
		||||
          this.getToken(this.$route.query?.code)
 | 
			
		||||
          .then(() => this.getUserInfo())
 | 
			
		||||
          .then(() => this.openForm())
 | 
			
		||||
        } else this.getCode(location.href)
 | 
			
		||||
      } else if (this.token) {//获取账号信息
 | 
			
		||||
        return this.getAccount()
 | 
			
		||||
      } else if (this.$route.query?.code) {//获取token
 | 
			
		||||
        return this.getToken(this.$route.query?.code)
 | 
			
		||||
      } else {//获取应用配置
 | 
			
		||||
        this.getCode(location.href)
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    openForm() {
 | 
			
		||||
      this.redirectTo("/askForm/askForm")
 | 
			
		||||
    },
 | 
			
		||||
    redirectTo(path) {
 | 
			
		||||
      let {query, hash} = this.$route
 | 
			
		||||
      delete query.app
 | 
			
		||||
      uni.redirectTo({
 | 
			
		||||
        url: `/pages${path}`, success: () => {
 | 
			
		||||
          this.$router.push({query, hash})
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
    gotoApp(app) {
 | 
			
		||||
      uni.reLaunch({url: '/pages/loading?app=' + app})
 | 
			
		||||
    },
 | 
			
		||||
    devGetCode() {
 | 
			
		||||
      this.getCode(location.origin + '/pages/loading#dev')
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  created() {
 | 
			
		||||
    uni.showLoading({
 | 
			
		||||
      title: "加载中"
 | 
			
		||||
    })
 | 
			
		||||
    this.initAccess()?.then(() => {
 | 
			
		||||
      uni.hideLoading()
 | 
			
		||||
      if (this.token) {
 | 
			
		||||
        if (this.currentApp.name) {
 | 
			
		||||
          this.redirectTo(this.currentApp.path)
 | 
			
		||||
        } else if (this.$route.query.url) {
 | 
			
		||||
          this.redirectTo(this.$route.query.url)
 | 
			
		||||
        } else {
 | 
			
		||||
          this.result = {
 | 
			
		||||
            status: "error",
 | 
			
		||||
            tips: "应用加载失败",
 | 
			
		||||
            btn: "重新加载",
 | 
			
		||||
            btnTap() {
 | 
			
		||||
              location.href = location.href?.replace("#error", '')
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      } else if (this.isDev) {
 | 
			
		||||
        this.result = {
 | 
			
		||||
          tips: "欢迎进入开发应用",
 | 
			
		||||
        }
 | 
			
		||||
      } else {
 | 
			
		||||
        this.result = {
 | 
			
		||||
          status: "error",
 | 
			
		||||
          tips: "应用加载失败",
 | 
			
		||||
          btn: "重新加载",
 | 
			
		||||
          btnTap() {
 | 
			
		||||
            location.href = location.href?.replace("#error", '')
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    })?.catch(() => {
 | 
			
		||||
      uni.navigateTo({url: './login'})
 | 
			
		||||
    })
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
.loading {
 | 
			
		||||
  height: 100%;
 | 
			
		||||
  position: relative;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-direction: column;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
 | 
			
		||||
  & > span {
 | 
			
		||||
    font-size: 36px;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .codeText {
 | 
			
		||||
    font-size: 24px;
 | 
			
		||||
    margin-top: 16px;
 | 
			
		||||
    padding: 4px 0;
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    text-align: center;
 | 
			
		||||
    background: #ccc;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .codeBtn {
 | 
			
		||||
    width: 180px;
 | 
			
		||||
    text-align: center;
 | 
			
		||||
    cursor: pointer;
 | 
			
		||||
    font-size: 24px;
 | 
			
		||||
    background: $uni-color-warning;
 | 
			
		||||
    color: #fff;
 | 
			
		||||
    padding: 8px;
 | 
			
		||||
    margin-top: 16px;
 | 
			
		||||
    border-radius: 8px;
 | 
			
		||||
    font-weight: normal;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .appsPane {
 | 
			
		||||
    justify-content: center;
 | 
			
		||||
    margin-top: 16px;
 | 
			
		||||
    padding: 0 16px;
 | 
			
		||||
 | 
			
		||||
    b {
 | 
			
		||||
      cursor: pointer;
 | 
			
		||||
      font-size: 24px;
 | 
			
		||||
      background: $uni-color-primary;
 | 
			
		||||
      color: #fff;
 | 
			
		||||
      padding: 8px;
 | 
			
		||||
      margin: 4px;
 | 
			
		||||
      border-radius: 8px;
 | 
			
		||||
      font-weight: normal;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										96
									
								
								src/pages/login.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,96 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <section class="login">
 | 
			
		||||
    <u-form :model="form" ref="loginForm" label-width="140">
 | 
			
		||||
      <u-form-item label="账号" prop="phone" :errory-type="['message']">
 | 
			
		||||
        <u-input v-model="form.phone" placeholder="请输入手机号"/>
 | 
			
		||||
      </u-form-item>
 | 
			
		||||
      <u-form-item label="验证码" prop="vcode">
 | 
			
		||||
        <u-input v-model="form.vcode" placeholder="请输入短信验证码"/>
 | 
			
		||||
        <u-verification-code ref="vcode" secords="60" @change="v=>tips=v"/>
 | 
			
		||||
        <div class="vcode" @tap="$u.debounce(getVCode)">{{ tips }}</div>
 | 
			
		||||
      </u-form-item>
 | 
			
		||||
    </u-form>
 | 
			
		||||
    <div bottom>
 | 
			
		||||
      <u-button type="primary" @tap="handleLogin">绑定并登录</u-button>
 | 
			
		||||
    </div>
 | 
			
		||||
  </section>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import {mapActions, mapState} from "vuex";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: "login",
 | 
			
		||||
  inject: ['root'],
 | 
			
		||||
  computed: {
 | 
			
		||||
    ...mapState(['lastPage']),
 | 
			
		||||
    rules() {
 | 
			
		||||
      return {
 | 
			
		||||
        phone: [{required: true, message: "请选择分组"}],
 | 
			
		||||
        vcode: [{required: true, message: "请选择快捷回复类型"}],
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  data() {
 | 
			
		||||
    return {
 | 
			
		||||
      form: {},
 | 
			
		||||
      tips: ''
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    ...mapActions(['getCode']),
 | 
			
		||||
    getVCode() {
 | 
			
		||||
      if (this.form.phone) {
 | 
			
		||||
        this.$http.post("/admin/user/sendCode", null, {
 | 
			
		||||
          withoutToken: 1,
 | 
			
		||||
          params: {phone: this.form.phone}
 | 
			
		||||
        }).then(() => {
 | 
			
		||||
          this.$u.toast("验证已发送!")
 | 
			
		||||
          this.$refs.vcode?.start()
 | 
			
		||||
        })
 | 
			
		||||
      } else {
 | 
			
		||||
        this.$u.toast("请先填写手机号!")
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    handleLogin() {
 | 
			
		||||
      this.$refs.loginForm.validate(v => {
 | 
			
		||||
        if (v) {
 | 
			
		||||
          let params = {
 | 
			
		||||
            ...this.form, code: this.$route.query?.code, then: res => {
 | 
			
		||||
              let last = uni.getStorageSync("lastApp")
 | 
			
		||||
              if (last) {
 | 
			
		||||
                this.$store.commit("login", [res?.token_type, res?.access_token].join(" ").trim())
 | 
			
		||||
                uni.removeStorageSync("lastApp")
 | 
			
		||||
                // this.root.getCode(location.origin + last)
 | 
			
		||||
                uni.reLaunch({url: "./loading?app=" + last})
 | 
			
		||||
              } else this.$u.toast("绑定成功,请重新打开应用页面!")
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
          this.$store.commit("bindAccount", params)
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  created() {
 | 
			
		||||
    !this.$route.query?.code && this.getCode()
 | 
			
		||||
  },
 | 
			
		||||
  mounted() {
 | 
			
		||||
    this.$nextTick(() => this.$refs.loginForm?.setRules(this.rules))
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
.login {
 | 
			
		||||
  border-top: 1px solid #D4D4D4;
 | 
			
		||||
  padding: 0 0 208px;
 | 
			
		||||
  background: #F5F5F5;
 | 
			
		||||
  box-sizing: border-box;
 | 
			
		||||
  height: 100%;
 | 
			
		||||
 | 
			
		||||
  .vcode {
 | 
			
		||||
    color: $uni-color-primary;
 | 
			
		||||
    cursor: pointer;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										398
									
								
								src/pages/meetingNotice/components/addMeeting.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,398 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="add-meeting">
 | 
			
		||||
    <div v-if="!userSelect">
 | 
			
		||||
      <div class="card">
 | 
			
		||||
        <header><em>*</em>会议标题</header>
 | 
			
		||||
        <input v-model="form.title" placeholder="请输入" :maxlength="30">
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="card">
 | 
			
		||||
        <header><em>*</em>起止时间</header>
 | 
			
		||||
        <u-row justify="between">
 | 
			
		||||
          <div class="time" @click="pick(0)">
 | 
			
		||||
            <span>{{form.startTime.time}}</span>
 | 
			
		||||
            <span>{{form.startTime.year}}年{{form.startTime.month}}月{{form.startTime.day}}日 周{{form.startTime.weekday}}</span>
 | 
			
		||||
          </div>
 | 
			
		||||
          <div class="arrow"></div>
 | 
			
		||||
          <div class="time" @click="pick(1)">
 | 
			
		||||
            <span>{{form.endTime.time}}</span>
 | 
			
		||||
            <span>{{form.endTime.year}}年{{form.endTime.month}}月{{form.endTime.day}}日 周{{form.endTime.weekday}}</span>
 | 
			
		||||
          </div>
 | 
			
		||||
        </u-row>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="card">
 | 
			
		||||
        <header><em>*</em>会议地点</header>
 | 
			
		||||
        <input v-model="form.address" placeholder="请输入" :maxlength="30">
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="card">
 | 
			
		||||
        <header><em>*</em>会议内容</header>
 | 
			
		||||
        <textarea v-model="form.content" placeholder="请输入" :maxlength="500"></textarea>
 | 
			
		||||
      </div>
 | 
			
		||||
 | 
			
		||||
      <div class="card">
 | 
			
		||||
        <AiUploader :multiple="true" type="file" :limit="9" placeholder="上传附件" @list="fileList" :def="form.files"></AiUploader>
 | 
			
		||||
      </div>
 | 
			
		||||
 | 
			
		||||
      <div class="card item-wrap" @click="select">
 | 
			
		||||
        <u-row justify="between" class="item" @click="userSelect=true">
 | 
			
		||||
          <header><em>*</em>参会人</header>
 | 
			
		||||
          <div class="right">
 | 
			
		||||
            <template v-if="!form.attendees.length">
 | 
			
		||||
              <span>请选择</span>
 | 
			
		||||
            </template>
 | 
			
		||||
            <template v-else>
 | 
			
		||||
              已选择<em>{{form.attendees.map(e=>e.name).slice(0,2).join("、")}}</em>等<em>{{form.attendees.length}}</em>人
 | 
			
		||||
            </template>
 | 
			
		||||
            <div class="right-arrow"></div>
 | 
			
		||||
          </div>
 | 
			
		||||
        </u-row>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="card item-wrap" style="margin-top: 0">
 | 
			
		||||
        <u-row justify="between" class="item">
 | 
			
		||||
          <header>参会提醒</header>
 | 
			
		||||
          <picker class="right" @change="beforeNoticeChange" :value="form.noticeBefore" range-key="dictName"
 | 
			
		||||
                  :range="$dict.getDict('meetingNoticeBefore')">
 | 
			
		||||
            <span>{{ form.noticeBefore !=null ? $dict.getDict('meetingNoticeBefore')[form.noticeBefore]["dictName"] : "请选择"}}</span>
 | 
			
		||||
            <div class="right-arrow"></div>
 | 
			
		||||
          </picker>
 | 
			
		||||
        </u-row>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="card item-wrap" style="margin-top: 0">
 | 
			
		||||
        <u-row justify="between" class="item">
 | 
			
		||||
          <header>确认提醒</header>
 | 
			
		||||
          <picker class="right" @change="afterNoticeChange" :value="form.noticeAfter" range-key="dictName"
 | 
			
		||||
                  :range="$dict.getDict('meetingNoticeAfter')">
 | 
			
		||||
            <span>{{form.noticeAfter !=null ? $dict.getDict('meetingNoticeAfter')[form.noticeAfter]["dictName"] : "请选择"}}</span>
 | 
			
		||||
            <div class="right-arrow"></div>
 | 
			
		||||
          </picker>
 | 
			
		||||
        </u-row>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="footer">
 | 
			
		||||
        <div @click="add(0)">保存草稿</div>
 | 
			
		||||
        <div @click="add(1)">发布会议</div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <u-picker mode="time" v-model="show" :params="params" @confirm="confirm"></u-picker>
 | 
			
		||||
    <AiBack ref="aiBack" v-if="!userSelect"/>
 | 
			
		||||
    <AiSelectEnterprise :visible.sync="userSelect" :value="form.attendees" v-if="userSelect" @change="change"></AiSelectEnterprise>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
  import AiBack from "../../../components/AiBack";
 | 
			
		||||
  import AiSelectEnterprise from "../../../components/AiSelectEnterprise/AiSelectEnterprise";
 | 
			
		||||
  import AiUploader from "../../../components/AiUploader";
 | 
			
		||||
 | 
			
		||||
  export default {
 | 
			
		||||
    name: "addMeeting",
 | 
			
		||||
    components: {AiBack,AiSelectEnterprise,AiUploader},
 | 
			
		||||
    data() {
 | 
			
		||||
      const initTime = {
 | 
			
		||||
        time: "",
 | 
			
		||||
        year: "",
 | 
			
		||||
        month: "",
 | 
			
		||||
        day: "",
 | 
			
		||||
        weekday: "",
 | 
			
		||||
        timestamp: "",
 | 
			
		||||
      }
 | 
			
		||||
      return {
 | 
			
		||||
        show: false,
 | 
			
		||||
        index: 0,
 | 
			
		||||
        list: [],
 | 
			
		||||
        form: {
 | 
			
		||||
          id: null,
 | 
			
		||||
          title: "",
 | 
			
		||||
          startTime: {...initTime},
 | 
			
		||||
          endTime: {...initTime},
 | 
			
		||||
          address: "",
 | 
			
		||||
          content: "",
 | 
			
		||||
          attendees: [],
 | 
			
		||||
          noticeBefore: 4,
 | 
			
		||||
          noticeAfter: 0,
 | 
			
		||||
          files: [],
 | 
			
		||||
        },
 | 
			
		||||
        userSelect: false,
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    onLoad(opt) {
 | 
			
		||||
      if(opt.id) {
 | 
			
		||||
        this.form.id = opt.id
 | 
			
		||||
        this.getDetail()
 | 
			
		||||
      }
 | 
			
		||||
      this.$dict.load("meetingNoticeBefore", "meetingNoticeAfter");
 | 
			
		||||
      this.$nextTick(()=>{
 | 
			
		||||
        let date = new Date();
 | 
			
		||||
        this.form.startTime.time = date.getHours()?.toString()?.padStart(2, "0") + ":" + date.getMinutes()?.toString()?.padStart(2, "0")
 | 
			
		||||
        this.form.startTime.year = date.getFullYear()
 | 
			
		||||
        this.form.startTime.month = (date.getMonth()+1)?.toString()?.padStart(2, "0")
 | 
			
		||||
        this.form.startTime.day = date.getDate()
 | 
			
		||||
        this.form.startTime.weekday = '日一二三四五六'.charAt(date.getDay())
 | 
			
		||||
        this.form.endTime = {...this.form.startTime}
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
    computed: {
 | 
			
		||||
      params() {
 | 
			
		||||
        return {
 | 
			
		||||
          year: true,
 | 
			
		||||
          month: true,
 | 
			
		||||
          day: true,
 | 
			
		||||
          hour: true,
 | 
			
		||||
          minute: true,
 | 
			
		||||
          timestamp: true,
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    methods: {
 | 
			
		||||
      fileList(e){
 | 
			
		||||
        this.form.files = e
 | 
			
		||||
      },
 | 
			
		||||
      change(e){
 | 
			
		||||
        this.form.attendees = e
 | 
			
		||||
      },
 | 
			
		||||
      beforeNoticeChange(e) {
 | 
			
		||||
        this.form.noticeBefore = e.detail.value
 | 
			
		||||
      },
 | 
			
		||||
      afterNoticeChange(e) {
 | 
			
		||||
        this.form.noticeAfter = e.detail.value
 | 
			
		||||
      },
 | 
			
		||||
 | 
			
		||||
      getDetail(){
 | 
			
		||||
        this.$http.post("/app/appmeetinginfo/info-id",null,{
 | 
			
		||||
          params:{
 | 
			
		||||
            id:this.form.id
 | 
			
		||||
          }
 | 
			
		||||
        }).then(res=>{
 | 
			
		||||
          if (res && res.data) {
 | 
			
		||||
            this.form.title = res.data.title
 | 
			
		||||
            this.form.address = res.data.address
 | 
			
		||||
            this.form.content = res.data.content
 | 
			
		||||
            this.form.attendees = res.data.attendees
 | 
			
		||||
            this.form.noticeBefore = res.data.noticeBefore
 | 
			
		||||
            this.form.noticeAfter = res.data.noticeAfter
 | 
			
		||||
            this.form.files = res.data.files
 | 
			
		||||
            this.form.startTime.time = res.data.startTime.split(" ")[1].substr(0, 5)
 | 
			
		||||
            this.form.startTime.year = res.data.startTime.split(" ")[0].split("-")[0]
 | 
			
		||||
            this.form.startTime.month = res.data.startTime.split(" ")[0].split("-")[1]
 | 
			
		||||
            this.form.startTime.day = res.data.startTime.split(" ")[0].split("-")[2]
 | 
			
		||||
            this.form.startTime.weekday = '日一二三四五六'.charAt(new Date(res.data.startTime.split(" ")[0]).getDay())
 | 
			
		||||
            this.form.startTime.timestamp = new Date(res.data.startTime).getTime()
 | 
			
		||||
 | 
			
		||||
            this.form.endTime.time = res.data.endTime.split(" ")[1].substr(0, 5)
 | 
			
		||||
            this.form.endTime.year = res.data.endTime.split(" ")[0].split("-")[0]
 | 
			
		||||
            this.form.endTime.month = res.data.endTime.split(" ")[0].split("-")[1]
 | 
			
		||||
            this.form.endTime.day = res.data.endTime.split(" ")[0].split("-")[2]
 | 
			
		||||
            this.form.endTime.weekday = '日一二三四五六'.charAt(new Date(res.data.endTime.split(" ")[0]).getDay())
 | 
			
		||||
            this.form.endTime.timestamp = new Date(res.data.endTime).getTime()
 | 
			
		||||
          }
 | 
			
		||||
        })
 | 
			
		||||
      },
 | 
			
		||||
      confirm(e) {
 | 
			
		||||
        if (new Date().getTime() / 1000 > e.timestamp) return this.$u.toast("选择时间不能小于当前时间")
 | 
			
		||||
        if (this.index == 0) {
 | 
			
		||||
          this.form.startTime = {...e}
 | 
			
		||||
          this.form.startTime.time = e.hour + ":" + (e.minute.length > 1 ? e.minute : ("0" + e.minute))
 | 
			
		||||
          this.form.startTime.weekday = '日一二三四五六'.charAt(new Date(e.timestamp * 1000).getDay())
 | 
			
		||||
        } else {
 | 
			
		||||
          if (this.form.startTime.timestamp >= e.timestamp) {
 | 
			
		||||
            return this.$u.toast("结束时间不能小于开始时间");
 | 
			
		||||
          }
 | 
			
		||||
          this.form.endTime = {...e}
 | 
			
		||||
          this.form.endTime.time = e.hour + ":" + (e.minute.length > 1 ? e.minute : ("0" + e.minute))
 | 
			
		||||
          this.form.endTime.weekday = '日一二三四五六'.charAt(new Date(e.timestamp * 1000).getDay())
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
 | 
			
		||||
      add(status) {
 | 
			
		||||
        if(status==1){
 | 
			
		||||
          if (!this.form.title) return this.$u.toast("请输入会议标题")
 | 
			
		||||
 | 
			
		||||
          if (this.form.startTime.timestamp >= this.form.endTime.timestamp) return this.$u.toast("结束时间不能小于开始时间")
 | 
			
		||||
 | 
			
		||||
          if (!this.form.address) return this.$u.toast("请输入会议地点")
 | 
			
		||||
 | 
			
		||||
          if (!this.form.content) return this.$u.toast("请输入会议内容")
 | 
			
		||||
 | 
			
		||||
          if(!this.form.attendees.length) return this.$u.toast("请选择参会人")
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.$http.post("/app/appmeetinginfo/add-update", {
 | 
			
		||||
          ...this.form,
 | 
			
		||||
          files:this.form.files.map(e=>e.id),
 | 
			
		||||
          status,
 | 
			
		||||
          startTime: this.form.startTime.year + "-" + this.form.startTime.month + "-" + this.form.startTime.day + " " + this.form.startTime.time + ":00",
 | 
			
		||||
          endTime: this.form.endTime.year + "-" + this.form.endTime.month + "-" + this.form.endTime.day + " " + this.form.endTime.time + ":00",
 | 
			
		||||
        }).then(res => {
 | 
			
		||||
          if (res.code == 0) {
 | 
			
		||||
            this.$u.toast(status == 1 ? "发布成功" : "保存成功")
 | 
			
		||||
            this.$refs["aiBack"].back()
 | 
			
		||||
          }
 | 
			
		||||
        })
 | 
			
		||||
      },
 | 
			
		||||
 | 
			
		||||
      pick(index) {
 | 
			
		||||
        this.index = index
 | 
			
		||||
        this.show = true
 | 
			
		||||
      },
 | 
			
		||||
      select() {
 | 
			
		||||
        uni.navigateTo({
 | 
			
		||||
          url: "/pages/meetingNotice/components/notice"
 | 
			
		||||
        })
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
  }
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
  .add-meeting {
 | 
			
		||||
    min-height: 100%;
 | 
			
		||||
    background: #F5F5F5;
 | 
			
		||||
    padding-bottom: 140px;
 | 
			
		||||
 | 
			
		||||
    .card {
 | 
			
		||||
      background-color: #FFFFFF;
 | 
			
		||||
      box-sizing: border-box;
 | 
			
		||||
      padding: 32px;
 | 
			
		||||
      margin-top: 16px;
 | 
			
		||||
 | 
			
		||||
      header {
 | 
			
		||||
        font-size: 32px;
 | 
			
		||||
        font-weight: 400;
 | 
			
		||||
        color: #333333;
 | 
			
		||||
 | 
			
		||||
        em {
 | 
			
		||||
          font-style: normal;
 | 
			
		||||
          font-size: 32px;
 | 
			
		||||
          color: #FF4466;
 | 
			
		||||
          margin-right: 8px;
 | 
			
		||||
          vertical-align: middle;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      input {
 | 
			
		||||
        margin: 32px 0 16px;
 | 
			
		||||
        box-sizing: border-box;
 | 
			
		||||
        padding: 0 16px;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      textarea {
 | 
			
		||||
        width: 100%;
 | 
			
		||||
        height: 160px;
 | 
			
		||||
        margin: 32px 0 16px;
 | 
			
		||||
        box-sizing: border-box;
 | 
			
		||||
        padding: 0 16px;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .u-row {
 | 
			
		||||
        margin-top: 34px;
 | 
			
		||||
 | 
			
		||||
        .time {
 | 
			
		||||
          display: flex;
 | 
			
		||||
          flex-direction: column;
 | 
			
		||||
 | 
			
		||||
          & > span:first-child {
 | 
			
		||||
            font-size: 60px;
 | 
			
		||||
            font-weight: 600;
 | 
			
		||||
            color: #333333;
 | 
			
		||||
            line-height: 84px;
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          & > span:last-child {
 | 
			
		||||
            font-size: 22px;
 | 
			
		||||
            color: #333333;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .arrow {
 | 
			
		||||
          width: 28px;
 | 
			
		||||
          height: 68px;
 | 
			
		||||
          overflow: hidden;
 | 
			
		||||
          position: relative;
 | 
			
		||||
          transform: rotate(180deg);
 | 
			
		||||
 | 
			
		||||
          &:before, &:after {
 | 
			
		||||
            content: "";
 | 
			
		||||
            width: 50px;
 | 
			
		||||
            height: 50px;
 | 
			
		||||
            position: absolute;
 | 
			
		||||
            transform: scaleY(1.3) translate(30%, -40px) rotate(45deg);
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          &:before {
 | 
			
		||||
            top: 59px;
 | 
			
		||||
            background-color: #CCCCCC;
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          &:after {
 | 
			
		||||
            left: 7px;
 | 
			
		||||
            top: 59px;
 | 
			
		||||
            background-color: #FFFFFF;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .item {
 | 
			
		||||
        height: 112px;
 | 
			
		||||
        box-shadow: 0px -1px 0px 0px #D8DDE6;
 | 
			
		||||
        margin-top: 0;
 | 
			
		||||
 | 
			
		||||
        .right {
 | 
			
		||||
          font-size: 28px;
 | 
			
		||||
          color: #999999;
 | 
			
		||||
          display: flex;
 | 
			
		||||
          align-items: center;
 | 
			
		||||
 | 
			
		||||
          em {
 | 
			
		||||
            font-style: normal;
 | 
			
		||||
            color: #1365DD;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .right-arrow {
 | 
			
		||||
          width: 16px;
 | 
			
		||||
          height: 16px;
 | 
			
		||||
          display: inline-block;
 | 
			
		||||
          border-top: 5px solid #CCCCCC;
 | 
			
		||||
          border-right: 5px solid #CCCCCC;
 | 
			
		||||
          transform: rotate(45deg);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .item-wrap {
 | 
			
		||||
      padding: 0 32px;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .footer {
 | 
			
		||||
      height: 112px;
 | 
			
		||||
      width: 100%;
 | 
			
		||||
      position: fixed;
 | 
			
		||||
      left: 0;
 | 
			
		||||
      bottom: 0;
 | 
			
		||||
      background-color: #FFFFFF;
 | 
			
		||||
      display: flex;
 | 
			
		||||
      align-items: center;
 | 
			
		||||
 | 
			
		||||
      & > div {
 | 
			
		||||
        font-size: 36px;
 | 
			
		||||
        color: #333333;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      & > div:first-child {
 | 
			
		||||
        width: 270px;
 | 
			
		||||
        height: 100%;
 | 
			
		||||
        display: flex;
 | 
			
		||||
        align-items: center;
 | 
			
		||||
        justify-content: center;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      & > div:last-child {
 | 
			
		||||
        width: calc(100% - 270px);
 | 
			
		||||
        height: 100%;
 | 
			
		||||
        color: #FFFFFF;
 | 
			
		||||
        display: flex;
 | 
			
		||||
        align-items: center;
 | 
			
		||||
        justify-content: center;
 | 
			
		||||
        background-color: #1365DD;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										231
									
								
								src/pages/meetingNotice/components/belongToMe.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,231 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="belong-to-me">
 | 
			
		||||
    <ai-top-fixed>
 | 
			
		||||
      <u-tabs :list="tabs" :is-scroll="false" :current="index" bar-width="88" :height="96" @change="change"></u-tabs>
 | 
			
		||||
    </ai-top-fixed>
 | 
			
		||||
    <div class="body">
 | 
			
		||||
      <template v-if="list.length">
 | 
			
		||||
        <div class="card" v-for="(item,index) in list" :key="index" @click="handleClick(item)">
 | 
			
		||||
          <header>{{item.title}}</header>
 | 
			
		||||
          <u-row justify="between">
 | 
			
		||||
            <div class="time">
 | 
			
		||||
              <span>{{item.startTime|formatTime}}</span>
 | 
			
		||||
              <span>{{item.startTime|formatDate(0)}}年{{item.startTime|formatDate(1)}}月{{item.startTime|formatDate(2)}}日 周{{item.startTime|formatWeek}}</span>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="arrow"></div>
 | 
			
		||||
            <div class="time">
 | 
			
		||||
              <span>{{item.endTime|formatTime}}</span>
 | 
			
		||||
              <span>{{item.endTime|formatDate(0)}}年{{item.endTime|formatDate(1)}}月{{item.endTime|formatDate(2)}}日 周{{item.endTime|formatWeek}}</span>
 | 
			
		||||
            </div>
 | 
			
		||||
          </u-row>
 | 
			
		||||
          <u-row class="info">
 | 
			
		||||
            <span>发起单位:</span>
 | 
			
		||||
            <span>{{item.unitName}}</span>
 | 
			
		||||
          </u-row>
 | 
			
		||||
          <u-gap height="20"></u-gap>
 | 
			
		||||
          <u-row class="info">
 | 
			
		||||
            <span>会议地点:</span>
 | 
			
		||||
            <span>{{item.address}}</span>
 | 
			
		||||
          </u-row>
 | 
			
		||||
          <div class="tag" :style="{background:'url(' + tag(item.status) + ')'}"></div>
 | 
			
		||||
        </div>
 | 
			
		||||
      </template>
 | 
			
		||||
      <template v-else>
 | 
			
		||||
        <ai-empty/>
 | 
			
		||||
      </template>
 | 
			
		||||
    </div>
 | 
			
		||||
    <AiBack/>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
  import AiTopFixed from "../../../components/AiTopFixed";
 | 
			
		||||
  import AiBack from "../../../components/AiBack";
 | 
			
		||||
  import AiEmpty from "../../../components/AiEmpty/AiEmpty";
 | 
			
		||||
 | 
			
		||||
  export default {
 | 
			
		||||
    name: "belongToMe",
 | 
			
		||||
    components: {AiTopFixed, AiBack, AiEmpty},
 | 
			
		||||
    data() {
 | 
			
		||||
      return {
 | 
			
		||||
        index: 0,
 | 
			
		||||
        current: 1,
 | 
			
		||||
        list: [],
 | 
			
		||||
        status: "加载更多",
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    onLoad() {
 | 
			
		||||
      this.getList()
 | 
			
		||||
    },
 | 
			
		||||
    computed: {
 | 
			
		||||
      tabs() {
 | 
			
		||||
        return [
 | 
			
		||||
          {name: "全部"},
 | 
			
		||||
          {name: "未开始"},
 | 
			
		||||
          {name: "进行中"},
 | 
			
		||||
          {name: "已取消"},
 | 
			
		||||
          {name: "已结束"},
 | 
			
		||||
        ]
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    methods: {
 | 
			
		||||
      tag(status) {
 | 
			
		||||
        return {
 | 
			
		||||
          "1": this.$cdn + 'common/1wks.png',
 | 
			
		||||
          "2": this.$cdn + 'common/1jxz.png',
 | 
			
		||||
          "3": this.$cdn + 'common/1yqx.png',
 | 
			
		||||
          "4": this.$cdn + 'common/1yjs.png'
 | 
			
		||||
        }[status]
 | 
			
		||||
      },
 | 
			
		||||
      getList() {
 | 
			
		||||
        this.$http.post("/app/appmeetinginfo/list", null, {
 | 
			
		||||
          params: {
 | 
			
		||||
            listType: 0,
 | 
			
		||||
            meetingStatus: this.index == 0 ? "-1" : this.index,
 | 
			
		||||
            size: 10,
 | 
			
		||||
            current: this.current
 | 
			
		||||
          }
 | 
			
		||||
        }).then(res => {
 | 
			
		||||
          if (res && res.data) {
 | 
			
		||||
            if (this.current > 1 && this.current > res.data.pages) {
 | 
			
		||||
              this.status = "已经到底啦"
 | 
			
		||||
            }
 | 
			
		||||
            this.list = this.current > 1 ? [...this.list, ...res.data.records] : res.data.records
 | 
			
		||||
          }
 | 
			
		||||
        })
 | 
			
		||||
      },
 | 
			
		||||
      handleClick({id}) {
 | 
			
		||||
        uni.navigateTo({
 | 
			
		||||
          url: "/pages/meetingNotice/components/detail?id=" + id
 | 
			
		||||
        })
 | 
			
		||||
      },
 | 
			
		||||
      change(e) {
 | 
			
		||||
        this.index = e
 | 
			
		||||
        this.current = 1
 | 
			
		||||
        this.getList()
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    onReachBottom() {
 | 
			
		||||
      this.current = this.current + 1;
 | 
			
		||||
      this.getList()
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    filters: {
 | 
			
		||||
      formatTime(date) {
 | 
			
		||||
        return date.split(" ")[1]?.substr(0, 5)
 | 
			
		||||
      },
 | 
			
		||||
      formatDate(date, i) {
 | 
			
		||||
        return date.split(" ")[0]?.split("-")[i]
 | 
			
		||||
      },
 | 
			
		||||
      formatWeek(date) {
 | 
			
		||||
        return "日一二三四五六".charAt(new Date(date.split(" ")[0]).getDay())
 | 
			
		||||
      },
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
  .belong-to-me {
 | 
			
		||||
    min-height: 100%;
 | 
			
		||||
    background-color: #F5F5F5;
 | 
			
		||||
 | 
			
		||||
    ::v-deep .content {
 | 
			
		||||
      padding: 0 !important;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .body {
 | 
			
		||||
      box-sizing: border-box;
 | 
			
		||||
      padding: 40px 32px;
 | 
			
		||||
 | 
			
		||||
      .card {
 | 
			
		||||
        background-color: #FFFFFF;
 | 
			
		||||
        box-sizing: border-box;
 | 
			
		||||
        padding: 32px;
 | 
			
		||||
        border-radius: 8px;
 | 
			
		||||
        margin-bottom: 32px;
 | 
			
		||||
        position: relative;
 | 
			
		||||
 | 
			
		||||
        &:last-child {
 | 
			
		||||
          margin-bottom: 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        & > header {
 | 
			
		||||
          font-size: 32px;
 | 
			
		||||
          font-weight: 600;
 | 
			
		||||
          color: #333333;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .time {
 | 
			
		||||
          display: flex;
 | 
			
		||||
          flex-direction: column;
 | 
			
		||||
          margin: 46px 0;
 | 
			
		||||
 | 
			
		||||
          & > span:first-child {
 | 
			
		||||
            font-size: 60px;
 | 
			
		||||
            font-weight: 600;
 | 
			
		||||
            color: #333333;
 | 
			
		||||
            line-height: 84px;
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          & > span:last-child {
 | 
			
		||||
            font-size: 22px;
 | 
			
		||||
            color: #333333;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .arrow {
 | 
			
		||||
          width: 28px;
 | 
			
		||||
          height: 68px;
 | 
			
		||||
          overflow: hidden;
 | 
			
		||||
          position: relative;
 | 
			
		||||
          transform: rotate(180deg);
 | 
			
		||||
 | 
			
		||||
          &:before, &:after {
 | 
			
		||||
            content: "";
 | 
			
		||||
            width: 50px;
 | 
			
		||||
            height: 50px;
 | 
			
		||||
            position: absolute;
 | 
			
		||||
            transform: scaleY(1.3) translate(30%, -40px) rotate(45deg);
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          &:before {
 | 
			
		||||
            top: 59px;
 | 
			
		||||
            background-color: #CCCCCC;
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          &:after {
 | 
			
		||||
            left: 7px;
 | 
			
		||||
            top: 59px;
 | 
			
		||||
            background-color: #FFFFFF;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .info {
 | 
			
		||||
          flex-wrap: nowrap;
 | 
			
		||||
 | 
			
		||||
          & > span:first-child {
 | 
			
		||||
            font-size: 30px;
 | 
			
		||||
            color: #999999;
 | 
			
		||||
            flex-shrink: 0;
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          & > span:last-child {
 | 
			
		||||
            font-size: 30px;
 | 
			
		||||
            color: #343D65;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .tag {
 | 
			
		||||
          width: 112px;
 | 
			
		||||
          height: 112px;
 | 
			
		||||
          background-repeat: no-repeat;
 | 
			
		||||
          background-size: 100% 100% !important;
 | 
			
		||||
          position: absolute;
 | 
			
		||||
          top: 0;
 | 
			
		||||
          right: 0;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										478
									
								
								src/pages/meetingNotice/components/detail.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,478 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="detail">
 | 
			
		||||
    <template v-if="!list">
 | 
			
		||||
      <div class="card">
 | 
			
		||||
        <header>{{ detail.title }}</header>
 | 
			
		||||
        <u-gap height="16"></u-gap>
 | 
			
		||||
        <u-row>
 | 
			
		||||
          <u-avatar :src="$cdn + 'common/xzh.png'" v-if="false"></u-avatar>
 | 
			
		||||
          <div class="u-avatar__img" v-else>{{ detail.userName && detail.userName.substr(-2) }}</div>
 | 
			
		||||
          <span>{{ detail.userName }}</span>
 | 
			
		||||
        </u-row>
 | 
			
		||||
        <u-gap height="32"></u-gap>
 | 
			
		||||
        <u-row>
 | 
			
		||||
          <img :src="$cdn + 'common/meeting.png'" alt="">
 | 
			
		||||
          <span :style="{color:color(detail.status)}">{{ $dict.getLabel('meetStatus', detail.status) }}</span>
 | 
			
		||||
        </u-row>
 | 
			
		||||
        <u-gap height="8"></u-gap>
 | 
			
		||||
        <u-row>
 | 
			
		||||
          <img :src="$cdn + 'common/date.png'" alt="">
 | 
			
		||||
          <span>{{ detail.startTime && detail.startTime.substr(0, 16) }} 至 {{ detail.endTime && detail.endTime.substr(0, 16) }}</span>
 | 
			
		||||
        </u-row>
 | 
			
		||||
        <u-gap height="8"></u-gap>
 | 
			
		||||
        <u-row>
 | 
			
		||||
          <img :src="$cdn + 'common/location.png'" alt="">
 | 
			
		||||
          <span>{{ detail.address }}</span>
 | 
			
		||||
        </u-row>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="card">
 | 
			
		||||
        <span>{{ detail.content }}</span>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="card" v-if="detail.files && detail.files.length">
 | 
			
		||||
        <div class="label">相关附件</div>
 | 
			
		||||
        <div class="file" v-for="(item,index) in detail.files" @click="preFile(item)" :key="index">
 | 
			
		||||
          <u-row justify="between">
 | 
			
		||||
            <label class="left">
 | 
			
		||||
              <img :src="$cdn + 'common/appendix.png'" alt="">
 | 
			
		||||
              <span>{{ item.fileName }}.{{ item.postfix }}</span>
 | 
			
		||||
            </label>
 | 
			
		||||
            <span>{{ item.fileSizeStr }}</span>
 | 
			
		||||
          </u-row>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="card item-wrap">
 | 
			
		||||
        <u-row justify="between">
 | 
			
		||||
          <span>参会人</span>
 | 
			
		||||
          <label class="right" @click="list=true">
 | 
			
		||||
            查看全部<em>{{ detail.attendees && detail.attendees.length }}</em>人
 | 
			
		||||
            <div class="right-arrow"></div>
 | 
			
		||||
          </label>
 | 
			
		||||
        </u-row>
 | 
			
		||||
      </div>
 | 
			
		||||
 | 
			
		||||
      <div class="footer" v-if="['1','2'].includes(detail.status) && detail.joinStatus==0">
 | 
			
		||||
        <div @click="updateStatus(0)">请假</div>
 | 
			
		||||
        <div @click="updateStatus(1)">确认会议</div>
 | 
			
		||||
      </div>
 | 
			
		||||
 | 
			
		||||
      <div class="footer" v-if="['1','2'].includes(detail.status) && detail.joinStatus!=0">
 | 
			
		||||
        <label>{{ detail.joinStatus|transform }}</label>
 | 
			
		||||
        <img :src="$cdn + tag(detail.joinStatus)" alt="">
 | 
			
		||||
      </div>
 | 
			
		||||
 | 
			
		||||
    </template>
 | 
			
		||||
    <template v-else>
 | 
			
		||||
      <div class="att-list">
 | 
			
		||||
        <AiTopFixed>
 | 
			
		||||
          <u-tabs :list="tabs" :current="current" height="96" :is-scroll="false" bar-width="192"
 | 
			
		||||
                  @change="change"></u-tabs>
 | 
			
		||||
        </AiTopFixed>
 | 
			
		||||
        <div v-for="(item,index) in detail.attendees && detail.attendees.filter(e=>e.joinStatus==current)" :key="index"
 | 
			
		||||
             class="att-wrap">
 | 
			
		||||
          <div class="left">
 | 
			
		||||
            <u-avatar :src="item.avatar || (($cdn + 'common/xztx.png'))" size="74" mode="square"></u-avatar>
 | 
			
		||||
            <text class="name" style="margin-left: 8px">{{ item.name }}</text>
 | 
			
		||||
          </div>
 | 
			
		||||
          <img :src="$cdn + 'common/phone.png'" alt="" @click="call(item)">
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </template>
 | 
			
		||||
    <AiBack visible eventName="back" @back="list=false"/>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import AiBack from "../../../components/AiBack";
 | 
			
		||||
import {mapActions} from "vuex";
 | 
			
		||||
import AiTopFixed from "../../../components/AiTopFixed";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: "detail",
 | 
			
		||||
  components: {AiBack, AiTopFixed},
 | 
			
		||||
  data() {
 | 
			
		||||
    return {
 | 
			
		||||
      id: null,
 | 
			
		||||
      detail: {},
 | 
			
		||||
      list: false,
 | 
			
		||||
      current: 0,
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  computed: {
 | 
			
		||||
    tabs() {
 | 
			
		||||
      return [
 | 
			
		||||
        {name: this.count(0) + "人未确认"},
 | 
			
		||||
        {name: this.count(1) + "人已确认"},
 | 
			
		||||
        {name: this.count(2) + "人已请假"},
 | 
			
		||||
      ]
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  onLoad(opt) {
 | 
			
		||||
    this.id = opt.id
 | 
			
		||||
    this.$dict.load("meetStatus").then(_ => this.getDetail())
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    count(sta) {
 | 
			
		||||
      return this.detail.attendees?.filter(e => e.joinStatus == sta)?.length;
 | 
			
		||||
    },
 | 
			
		||||
    change(index) {
 | 
			
		||||
      this.current = index;
 | 
			
		||||
    },
 | 
			
		||||
    call(item) {
 | 
			
		||||
      if (item.phone) {
 | 
			
		||||
        uni.makePhoneCall({
 | 
			
		||||
          phoneNumber: item.phone
 | 
			
		||||
        });
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    ...mapActions(['previewFile', 'injectJWeixin']),
 | 
			
		||||
    preFile(e) {
 | 
			
		||||
      if ([".jpg", ".png", ".gif"].includes(e.postfix.toLowerCase())) {
 | 
			
		||||
        uni.previewImage({
 | 
			
		||||
          current: e.url,
 | 
			
		||||
          urls: [e.url]
 | 
			
		||||
        })
 | 
			
		||||
      } else {
 | 
			
		||||
        this.previewFile({...e})
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    tag(status) {
 | 
			
		||||
      return {
 | 
			
		||||
        "1": "common/2confirmed2.png",
 | 
			
		||||
        "2": "common/2absent2.png"
 | 
			
		||||
      }[status]
 | 
			
		||||
    },
 | 
			
		||||
    updateStatus(status) {
 | 
			
		||||
      this.$http.post(status == 0 ? "/app/appmeetinginfo/absent" : "/app/appmeetinginfo/confirm", null, {
 | 
			
		||||
        params: {
 | 
			
		||||
          meetingId: this.id,
 | 
			
		||||
          reason: status == 0 ? "" : null
 | 
			
		||||
        }
 | 
			
		||||
      }).then(res => {
 | 
			
		||||
        if (res.code == 0) {
 | 
			
		||||
          this.$u.toast(status == 0 ? "请假成功" : "确认成功")
 | 
			
		||||
          this.getDetail()
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
    color(status) {
 | 
			
		||||
      if (status == 1) {
 | 
			
		||||
        return "#FF8822"
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (status == 2) {
 | 
			
		||||
        return "#1365DD"
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (status == 3) {
 | 
			
		||||
        return "#FF4466"
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      return "#343D65"
 | 
			
		||||
    },
 | 
			
		||||
    getDetail() {
 | 
			
		||||
      this.$http.post("/app/appmeetinginfo/info-id", null, {
 | 
			
		||||
        params: {id: this.id}
 | 
			
		||||
      }).then(res => {
 | 
			
		||||
        if (res && res.data) {
 | 
			
		||||
          this.detail = res.data
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  filters: {
 | 
			
		||||
    transform(status) {
 | 
			
		||||
      if (status == 1) {
 | 
			
		||||
        return "已确认"
 | 
			
		||||
      }
 | 
			
		||||
      if (status == 2) {
 | 
			
		||||
        return "已请假"
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
.detail {
 | 
			
		||||
  min-height: 100%;
 | 
			
		||||
  background-color: #F5F5F5;
 | 
			
		||||
  padding-bottom: 140px;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  ::v-deep .AiTopFixed {
 | 
			
		||||
    margin-bottom: 16px;
 | 
			
		||||
 | 
			
		||||
    .content {
 | 
			
		||||
      padding: 0 !important;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  .att-list {
 | 
			
		||||
    min-height: 100%;
 | 
			
		||||
 | 
			
		||||
    .att-wrap {
 | 
			
		||||
      display: flex;
 | 
			
		||||
      height: 112px;
 | 
			
		||||
      align-items: center;
 | 
			
		||||
      justify-content: space-between;
 | 
			
		||||
      background-color: #ffffff;
 | 
			
		||||
      box-sizing: border-box;
 | 
			
		||||
      padding: 0 50px;
 | 
			
		||||
      border-bottom: 1px solid #E4E5E6;
 | 
			
		||||
 | 
			
		||||
      .left {
 | 
			
		||||
        display: flex;
 | 
			
		||||
        align-items: center;
 | 
			
		||||
 | 
			
		||||
        &:after {
 | 
			
		||||
          content: "";
 | 
			
		||||
          position: absolute;
 | 
			
		||||
          right: 0;
 | 
			
		||||
          bottom: 0;
 | 
			
		||||
          width: 622px;
 | 
			
		||||
          height: 2px;
 | 
			
		||||
          background-color: rgba(216, 221, 230, 0.5);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .name {
 | 
			
		||||
          font-size: 30px;
 | 
			
		||||
          font-weight: 600;
 | 
			
		||||
          color: #333333;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      & > img {
 | 
			
		||||
        width: 48px;
 | 
			
		||||
        height: 48px;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .card {
 | 
			
		||||
    background-color: #FFFFFF;
 | 
			
		||||
    margin-bottom: 8px;
 | 
			
		||||
    box-sizing: border-box;
 | 
			
		||||
    padding: 16px 32px;
 | 
			
		||||
 | 
			
		||||
    header {
 | 
			
		||||
      font-size: 40px;
 | 
			
		||||
      font-weight: 600;
 | 
			
		||||
      color: #333333;
 | 
			
		||||
      line-height: 64px;
 | 
			
		||||
      letter-spacing: 1px;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .u-row {
 | 
			
		||||
      & > div {
 | 
			
		||||
        background-color: #2266FF;
 | 
			
		||||
        border-radius: 50%;
 | 
			
		||||
        text-align: center;
 | 
			
		||||
        font-size: 22px;
 | 
			
		||||
        font-weight: bold;
 | 
			
		||||
        color: #FFFFFF;
 | 
			
		||||
        display: flex;
 | 
			
		||||
        align-items: center;
 | 
			
		||||
        justify-content: center;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      & > span {
 | 
			
		||||
        font-size: 30px;
 | 
			
		||||
        color: #343D65;
 | 
			
		||||
        margin-left: 16px;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      ::v-deep .u-avatar__img {
 | 
			
		||||
        width: 56px;
 | 
			
		||||
        height: 56px;
 | 
			
		||||
        vertical-align: middle;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      img {
 | 
			
		||||
        width: 48px;
 | 
			
		||||
        height: 48px;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    & > span {
 | 
			
		||||
      font-size: 32px;
 | 
			
		||||
      color: #333333;
 | 
			
		||||
      line-height: 48px;
 | 
			
		||||
      letter-spacing: 1px;
 | 
			
		||||
      display: inline-block;
 | 
			
		||||
      box-sizing: border-box;
 | 
			
		||||
      padding: 16px 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .label {
 | 
			
		||||
      height: 96px;
 | 
			
		||||
      font-size: 32px;
 | 
			
		||||
      color: #333333;
 | 
			
		||||
      display: flex;
 | 
			
		||||
      align-items: center;
 | 
			
		||||
      margin-bottom: 16px;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .file {
 | 
			
		||||
      height: 128px;
 | 
			
		||||
      background: #FFFFFF;
 | 
			
		||||
      border-radius: 8px;
 | 
			
		||||
      border: 1px solid #CCCCCC;
 | 
			
		||||
      box-sizing: border-box;
 | 
			
		||||
      padding: 0 16px;
 | 
			
		||||
      margin-bottom: 32px;
 | 
			
		||||
 | 
			
		||||
      & > .u-row {
 | 
			
		||||
        height: 100%;
 | 
			
		||||
 | 
			
		||||
        .left {
 | 
			
		||||
          width: 522px;
 | 
			
		||||
          display: flex;
 | 
			
		||||
          align-items: center;
 | 
			
		||||
 | 
			
		||||
          & > img {
 | 
			
		||||
            width: 96px;
 | 
			
		||||
            height: 96px;
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          & > span {
 | 
			
		||||
            font-size: 32px;
 | 
			
		||||
            color: #333333;
 | 
			
		||||
            display: inline-block;
 | 
			
		||||
            line-height: 44px;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        & > span {
 | 
			
		||||
          font-size: 28px;
 | 
			
		||||
          color: #999999;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .active {
 | 
			
		||||
      background-color: #F3F6F9;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .name {
 | 
			
		||||
      font-size: 32px;
 | 
			
		||||
      font-weight: 400;
 | 
			
		||||
      color: #333333;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .wrap {
 | 
			
		||||
      height: 112px;
 | 
			
		||||
      display: flex;
 | 
			
		||||
      align-items: center;
 | 
			
		||||
      position: relative;
 | 
			
		||||
 | 
			
		||||
      &:after {
 | 
			
		||||
        content: "";
 | 
			
		||||
        position: absolute;
 | 
			
		||||
        right: 0;
 | 
			
		||||
        bottom: 0;
 | 
			
		||||
        width: 622px;
 | 
			
		||||
        height: 2px;
 | 
			
		||||
        background-color: rgba(216, 221, 230, 0.5);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      & > label {
 | 
			
		||||
        width: 80px;
 | 
			
		||||
        height: 80px;
 | 
			
		||||
        border-radius: 50%;
 | 
			
		||||
        background-color: #4E8EEE;
 | 
			
		||||
        font-size: 28px;
 | 
			
		||||
        font-weight: 600;
 | 
			
		||||
        color: #FFFFFF;
 | 
			
		||||
        display: flex;
 | 
			
		||||
        align-items: center;
 | 
			
		||||
        justify-content: center;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .item-wrap {
 | 
			
		||||
    height: 112px;
 | 
			
		||||
    padding: 0 32px;
 | 
			
		||||
 | 
			
		||||
    .u-row {
 | 
			
		||||
      height: 100%;
 | 
			
		||||
 | 
			
		||||
      & > span {
 | 
			
		||||
        font-size: 32px;
 | 
			
		||||
        font-weight: 400;
 | 
			
		||||
        color: #333333;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .right {
 | 
			
		||||
      font-size: 28px;
 | 
			
		||||
      color: #999999;
 | 
			
		||||
      display: flex;
 | 
			
		||||
      align-items: center;
 | 
			
		||||
 | 
			
		||||
      em {
 | 
			
		||||
        font-style: normal;
 | 
			
		||||
        color: #1365DD;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .right-arrow {
 | 
			
		||||
        width: 16px;
 | 
			
		||||
        height: 16px;
 | 
			
		||||
        border-top: 5px solid #CCCCCC;
 | 
			
		||||
        border-right: 5px solid #CCCCCC;
 | 
			
		||||
        transform: rotate(45deg);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .footer {
 | 
			
		||||
    height: 112px;
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    position: fixed;
 | 
			
		||||
    left: 0;
 | 
			
		||||
    bottom: 0;
 | 
			
		||||
    background-color: #FFFFFF;
 | 
			
		||||
    display: flex;
 | 
			
		||||
    align-items: center;
 | 
			
		||||
    justify-content: center;
 | 
			
		||||
 | 
			
		||||
    & > div {
 | 
			
		||||
      font-size: 36px;
 | 
			
		||||
      color: #333333;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    & > div:first-child {
 | 
			
		||||
      width: 270px;
 | 
			
		||||
      height: 100%;
 | 
			
		||||
      display: flex;
 | 
			
		||||
      align-items: center;
 | 
			
		||||
      justify-content: center;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    & > div:last-child {
 | 
			
		||||
      width: calc(100% - 270px);
 | 
			
		||||
      height: 100%;
 | 
			
		||||
      color: #FFFFFF;
 | 
			
		||||
      display: flex;
 | 
			
		||||
      align-items: center;
 | 
			
		||||
      justify-content: center;
 | 
			
		||||
      background-color: #1365DD;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    & > label {
 | 
			
		||||
      font-size: 36px;
 | 
			
		||||
      font-weight: 400;
 | 
			
		||||
      color: #999999;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    img {
 | 
			
		||||
      width: 158px;
 | 
			
		||||
      height: 104px;
 | 
			
		||||
      position: absolute;
 | 
			
		||||
      right: 0;
 | 
			
		||||
      top: 0;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										225
									
								
								src/pages/meetingNotice/components/meetingList.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,225 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="meeting-list">
 | 
			
		||||
    <div class="card" v-for="(item,index) in list" :key="index" @click="detail(item)">
 | 
			
		||||
      <header>
 | 
			
		||||
        <span>{{item.title}}</span>
 | 
			
		||||
        <span>
 | 
			
		||||
          <span v-if="index==2">保存于</span>
 | 
			
		||||
          {{item.createTime}}</span>
 | 
			
		||||
      </header>
 | 
			
		||||
      <u-row justify="between">
 | 
			
		||||
        <div class="time">
 | 
			
		||||
          <span>{{item.startTime|format}}</span>
 | 
			
		||||
          <span>{{item.startTime|formatDate(0)}}年{{item.startTime|formatDate(1)}}月{{item.startTime|formatDate(2)}}日 周{{item.startTime|formatWeek}}</span>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="arrow"></div>
 | 
			
		||||
        <div class="time">
 | 
			
		||||
          <span>{{item.endTime|format}}</span>
 | 
			
		||||
          <span>{{item.endTime|formatDate(0)}}年{{item.endTime|formatDate(1)}}月{{item.endTime|formatDate(2)}}日 周{{item.endTime|formatWeek}}</span>
 | 
			
		||||
        </div>
 | 
			
		||||
      </u-row>
 | 
			
		||||
      <u-row class="info">
 | 
			
		||||
        <span>发起人员:</span>
 | 
			
		||||
        <span>{{item.userName}}</span>
 | 
			
		||||
      </u-row>
 | 
			
		||||
      <u-gap height="20"></u-gap>
 | 
			
		||||
      <u-row class="info">
 | 
			
		||||
        <span>会议地点:</span>
 | 
			
		||||
        <span>{{item.address}}</span>
 | 
			
		||||
      </u-row>
 | 
			
		||||
        <div class="tag" v-if="item.status!=0" :style="{background:'url(' + $cdn + tag(item.status) +')'}"></div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <u-loadmore :status="status" v-if="list.length"/>
 | 
			
		||||
    <AiEmpty v-if="!list.length"></AiEmpty>
 | 
			
		||||
    <AiBack/>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
  import AiBack from "../../../components/AiBack";
 | 
			
		||||
  import AiEmpty from "../../../components/AiEmpty/AiEmpty";
 | 
			
		||||
 | 
			
		||||
  export default {
 | 
			
		||||
    name: "meetingList",
 | 
			
		||||
    components: {AiBack, AiEmpty},
 | 
			
		||||
    data() {
 | 
			
		||||
      return {
 | 
			
		||||
        index: null,
 | 
			
		||||
        list: [],
 | 
			
		||||
        current: 1,
 | 
			
		||||
        status: "加载更多",
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    onLoad(opt) {
 | 
			
		||||
      this.index = opt.index
 | 
			
		||||
      uni.setNavigationBarTitle({
 | 
			
		||||
        title: opt.index == 0 ? "历史会议" : "草稿箱"
 | 
			
		||||
      });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    methods: {
 | 
			
		||||
      detail({id}) {
 | 
			
		||||
        let url
 | 
			
		||||
        if (this.index == 2) {
 | 
			
		||||
          url = "/pages/meetingNotice/components/addMeeting?id=" + id
 | 
			
		||||
        } else {
 | 
			
		||||
          url = "/pages/meetingNotice/components/detail?id=" + id
 | 
			
		||||
        }
 | 
			
		||||
        uni.navigateTo({url})
 | 
			
		||||
      },
 | 
			
		||||
      tag(status) {
 | 
			
		||||
        return {
 | 
			
		||||
          "1": 'common/1wks.png',
 | 
			
		||||
          "2": 'common/1jxz.png',
 | 
			
		||||
          "3": 'common/1yqx.png',
 | 
			
		||||
          "4": 'common/1yjs.png'
 | 
			
		||||
        }[status]
 | 
			
		||||
      },
 | 
			
		||||
      getData() {
 | 
			
		||||
        this.$http.post("/app/appmeetinginfo/list", null, {
 | 
			
		||||
          params: {
 | 
			
		||||
            listType: this.index == 0 ? "2" : '0',
 | 
			
		||||
            meetingStatus: this.index == 0 ? "4" : "0",
 | 
			
		||||
            size: 10,
 | 
			
		||||
            current: this.current,
 | 
			
		||||
          }
 | 
			
		||||
        }).then(res => {
 | 
			
		||||
          if (res && res.data) {
 | 
			
		||||
            if (this.current > 1 && this.current > res.data.pages) {
 | 
			
		||||
              this.status = "已经到底啦"
 | 
			
		||||
            }
 | 
			
		||||
            this.list = this.current > 1 ? [...this.list, ...res.data.records] : res.data.records
 | 
			
		||||
          }
 | 
			
		||||
        })
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    filters: {
 | 
			
		||||
      format(date) {
 | 
			
		||||
        return date.split(" ")[1].substr(0, 5)
 | 
			
		||||
      },
 | 
			
		||||
      formatDate(date, index) {
 | 
			
		||||
        return date.split(" ")[0].split("-")[index]
 | 
			
		||||
      },
 | 
			
		||||
      formatWeek(date) {
 | 
			
		||||
        return "日一二三四五六".charAt((new Date(date.split(" ")[0]).getDay()))
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    onShow(){
 | 
			
		||||
      this.getData()
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    onReachBottom() {
 | 
			
		||||
      this.current = this.current + 1;
 | 
			
		||||
      this.getData()
 | 
			
		||||
    },
 | 
			
		||||
  }
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
  .meeting-list {
 | 
			
		||||
    min-height: 100%;
 | 
			
		||||
    background-color: #F5F5F5;
 | 
			
		||||
    box-sizing: border-box;
 | 
			
		||||
    padding: 32px;
 | 
			
		||||
 | 
			
		||||
    .card {
 | 
			
		||||
      background-color: #FFFFFF;
 | 
			
		||||
      box-sizing: border-box;
 | 
			
		||||
      padding: 32px;
 | 
			
		||||
      border-radius: 8px;
 | 
			
		||||
      margin-bottom: 32px;
 | 
			
		||||
      position: relative;
 | 
			
		||||
 | 
			
		||||
      &:last-child {
 | 
			
		||||
        margin-bottom: 0;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      & > header {
 | 
			
		||||
        font-size: 32px;
 | 
			
		||||
        font-weight: 600;
 | 
			
		||||
        color: #333333;
 | 
			
		||||
        display: flex;
 | 
			
		||||
        flex-direction: column;
 | 
			
		||||
 | 
			
		||||
        & > span:last-child {
 | 
			
		||||
          font-size: 28px;
 | 
			
		||||
          font-weight: 400;
 | 
			
		||||
          color: #999999;
 | 
			
		||||
          margin-top: 10px;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .time {
 | 
			
		||||
        display: flex;
 | 
			
		||||
        flex-direction: column;
 | 
			
		||||
        margin: 46px 0;
 | 
			
		||||
 | 
			
		||||
        & > span:first-child {
 | 
			
		||||
          font-size: 60px;
 | 
			
		||||
          font-weight: 600;
 | 
			
		||||
          color: #333333;
 | 
			
		||||
          line-height: 84px;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        & > span:last-child {
 | 
			
		||||
          font-size: 22px;
 | 
			
		||||
          color: #333333;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .arrow {
 | 
			
		||||
        width: 28px;
 | 
			
		||||
        height: 68px;
 | 
			
		||||
        overflow: hidden;
 | 
			
		||||
        position: relative;
 | 
			
		||||
        transform: rotate(180deg);
 | 
			
		||||
 | 
			
		||||
        &:before, &:after {
 | 
			
		||||
          content: "";
 | 
			
		||||
          width: 50px;
 | 
			
		||||
          height: 50px;
 | 
			
		||||
          position: absolute;
 | 
			
		||||
          transform: scaleY(1.3) translate(30%, -40px) rotate(45deg);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        &:before {
 | 
			
		||||
          top: 59px;
 | 
			
		||||
          background-color: #CCCCCC;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        &:after {
 | 
			
		||||
          left: 7px;
 | 
			
		||||
          top: 59px;
 | 
			
		||||
          background-color: #FFFFFF;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .info {
 | 
			
		||||
        flex-wrap: nowrap;
 | 
			
		||||
        & > span:first-child {
 | 
			
		||||
          flex-shrink: 0;
 | 
			
		||||
          font-size: 30px;
 | 
			
		||||
          color: #999999;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        & > span:last-child {
 | 
			
		||||
          font-size: 30px;
 | 
			
		||||
          color: #343D65;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .tag {
 | 
			
		||||
        width: 112px;
 | 
			
		||||
        height: 112px;
 | 
			
		||||
        background-repeat: no-repeat !important;
 | 
			
		||||
        background-size: 100% 100% !important;
 | 
			
		||||
        position: absolute;
 | 
			
		||||
        top: 0;
 | 
			
		||||
        right: 0;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										254
									
								
								src/pages/meetingNotice/meetingNotice.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,254 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="meeting">
 | 
			
		||||
    <ai-top-fixed>
 | 
			
		||||
      <u-grid :col="3" :border="false">
 | 
			
		||||
        <u-grid-item v-for="(item,index) in grid" :key="index" :custom-style="{padding:'14px 0'}" @click="handleClick(index)">
 | 
			
		||||
          <u-icon :name="item.icon" :size="64"></u-icon>
 | 
			
		||||
          <view class="label">{{item.label}}</view>
 | 
			
		||||
        </u-grid-item>
 | 
			
		||||
      </u-grid>
 | 
			
		||||
    </ai-top-fixed>
 | 
			
		||||
    <div class="body">
 | 
			
		||||
      <header>待参加的会议</header>
 | 
			
		||||
      <template v-if="meetingList.length">
 | 
			
		||||
        <div class="card" v-for="(item,index) in meetingList" :key="index" @click="detail(item)">
 | 
			
		||||
          <header>{{item.title}}</header>
 | 
			
		||||
          <u-row justify="between">
 | 
			
		||||
            <div class="time">
 | 
			
		||||
              <span>{{item.startTime|format}}</span>
 | 
			
		||||
              <span>{{item.startTime|formatDate(0)}}年{{item.startTime|formatDate(1)}}月{{item.startTime|formatDate(2)}}日 周{{item.startTime|formatWeek}}</span>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="arrow"></div>
 | 
			
		||||
            <div class="time">
 | 
			
		||||
              <span>{{item.endTime|format}}</span>
 | 
			
		||||
              <span>{{item.endTime|formatDate(0)}}年{{item.endTime|formatDate(1)}}月{{item.endTime|formatDate(2)}}日 周{{item.endTime|formatWeek}}</span>
 | 
			
		||||
            </div>
 | 
			
		||||
          </u-row>
 | 
			
		||||
          <u-row class="info">
 | 
			
		||||
            <span>发起人员:</span>
 | 
			
		||||
            <span>{{item.userName}}</span>
 | 
			
		||||
          </u-row>
 | 
			
		||||
          <u-gap height="20"></u-gap>
 | 
			
		||||
          <u-row class="info">
 | 
			
		||||
            <span>会议地点:</span>
 | 
			
		||||
            <span>{{item.address}}</span>
 | 
			
		||||
          </u-row>
 | 
			
		||||
          <div class="tag" :style="{background:'url(' + $cdn + tag(item.joinStatus) + ')'}"></div>
 | 
			
		||||
        </div>
 | 
			
		||||
      </template>
 | 
			
		||||
      <template v-else>
 | 
			
		||||
        <ai-empty/>
 | 
			
		||||
      </template>
 | 
			
		||||
    </div>
 | 
			
		||||
    <u-divider bg-color="#F5F5F5" v-if="meetingList.length">已经到底啦</u-divider>
 | 
			
		||||
    <ai-add @add="add"/>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
  import AiEmpty from "../../components/AiEmpty/AiEmpty";
 | 
			
		||||
  import AiTopFixed from "../../components/AiTopFixed";
 | 
			
		||||
  import AiAdd from "../../components/AiAdd";
 | 
			
		||||
 | 
			
		||||
  export default {
 | 
			
		||||
    name: "meetingNotice",
 | 
			
		||||
    components: {AiEmpty, AiTopFixed, AiAdd},
 | 
			
		||||
    data() {
 | 
			
		||||
      return {
 | 
			
		||||
        meetingList:[]
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    computed: {
 | 
			
		||||
      grid() {
 | 
			
		||||
        return [
 | 
			
		||||
          {
 | 
			
		||||
            icon: this.$cdn + "/common/iconlshy.png",
 | 
			
		||||
            label: "历史会议"
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            icon: this.$cdn + "/common/iconwfqd.png",
 | 
			
		||||
            label: "我发起的"
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            icon: this.$cdn + "/common/iconcgx.png",
 | 
			
		||||
            label: "草稿箱"
 | 
			
		||||
          }
 | 
			
		||||
        ]
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    methods: {
 | 
			
		||||
      tag(status){
 | 
			
		||||
        return {
 | 
			
		||||
          "0":"common/1wqr.png",
 | 
			
		||||
          "1":"common/1yqr.png",
 | 
			
		||||
          "2":"common/1yqj.png",
 | 
			
		||||
        }[status]
 | 
			
		||||
      },
 | 
			
		||||
      detail({id}){
 | 
			
		||||
        uni.navigateTo({
 | 
			
		||||
          url:"/pages/meetingNotice/components/detail?id=" + id
 | 
			
		||||
        })
 | 
			
		||||
      },
 | 
			
		||||
      getData() {
 | 
			
		||||
        this.$http.post("/app/appmeetinginfo/list", null, {
 | 
			
		||||
          params: {
 | 
			
		||||
            listType: "1",
 | 
			
		||||
            meetingStatus: "1|2",
 | 
			
		||||
            size: 999
 | 
			
		||||
          }
 | 
			
		||||
        }).then(res=>{
 | 
			
		||||
          if(res && res.data){
 | 
			
		||||
            this.meetingList = res.data.records
 | 
			
		||||
          }
 | 
			
		||||
        })
 | 
			
		||||
      },
 | 
			
		||||
      handleClick(index){
 | 
			
		||||
        let url
 | 
			
		||||
        if(index==0 || index==2){
 | 
			
		||||
          url="/pages/meetingNotice/components/meetingList?index=" + index
 | 
			
		||||
        }else if(index==1){
 | 
			
		||||
          url="/pages/meetingNotice/components/belongToMe"
 | 
			
		||||
        }
 | 
			
		||||
        uni.navigateTo({url})
 | 
			
		||||
      },
 | 
			
		||||
      add() {
 | 
			
		||||
        uni.navigateTo({
 | 
			
		||||
          url:"/pages/meetingNotice/components/addMeeting"
 | 
			
		||||
        })
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    filters:{
 | 
			
		||||
      format(date){
 | 
			
		||||
        return date.split(" ")[1].substr(0,5)
 | 
			
		||||
      },
 | 
			
		||||
      formatDate(date,index){
 | 
			
		||||
        return date.split(" ")[0].split("-")[index]
 | 
			
		||||
      },
 | 
			
		||||
      formatWeek(date){
 | 
			
		||||
        return "日一二三四五六".charAt((new Date(date.split(" ")[0]).getDay()))
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    onShow(){
 | 
			
		||||
     this.getData()
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
  .meeting {
 | 
			
		||||
    min-height: 100%;
 | 
			
		||||
    background: #F5F5F5;
 | 
			
		||||
    padding-bottom: 48px;
 | 
			
		||||
 | 
			
		||||
    .label {
 | 
			
		||||
      font-size: 28px;
 | 
			
		||||
      font-weight: 400;
 | 
			
		||||
      color: #333333;
 | 
			
		||||
      line-height: 48px;
 | 
			
		||||
      margin-top: 8px;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .body {
 | 
			
		||||
      box-sizing: border-box;
 | 
			
		||||
      padding: 40px 32px;
 | 
			
		||||
 | 
			
		||||
      & > header {
 | 
			
		||||
        font-size: 36px;
 | 
			
		||||
        font-weight: 600;
 | 
			
		||||
        color: #333333;
 | 
			
		||||
        margin-bottom: 38px;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .card {
 | 
			
		||||
        background-color: #FFFFFF;
 | 
			
		||||
        box-sizing: border-box;
 | 
			
		||||
        padding: 32px;
 | 
			
		||||
        border-radius: 8px;
 | 
			
		||||
        margin-bottom: 32px;
 | 
			
		||||
        position: relative;
 | 
			
		||||
 | 
			
		||||
        &:last-child {
 | 
			
		||||
          margin-bottom: 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        & > header {
 | 
			
		||||
          font-size: 32px;
 | 
			
		||||
          font-weight: 600;
 | 
			
		||||
          color: #333333;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .time {
 | 
			
		||||
          display: flex;
 | 
			
		||||
          flex-direction: column;
 | 
			
		||||
          margin: 46px 0;
 | 
			
		||||
 | 
			
		||||
          & > span:first-child {
 | 
			
		||||
            font-size: 60px;
 | 
			
		||||
            font-weight: 600;
 | 
			
		||||
            color: #333333;
 | 
			
		||||
            line-height: 84px;
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          & > span:last-child {
 | 
			
		||||
            font-size: 22px;
 | 
			
		||||
            color: #333333;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .arrow {
 | 
			
		||||
          width: 28px;
 | 
			
		||||
          height: 68px;
 | 
			
		||||
          overflow: hidden;
 | 
			
		||||
          position: relative;
 | 
			
		||||
          transform: rotate(180deg);
 | 
			
		||||
 | 
			
		||||
          &:before, &:after {
 | 
			
		||||
            content: "";
 | 
			
		||||
            width: 50px;
 | 
			
		||||
            height: 50px;
 | 
			
		||||
            position: absolute;
 | 
			
		||||
            transform: scaleY(1.3) translate(30%, -40px) rotate(45deg);
 | 
			
		||||
          }
 | 
			
		||||
          &:before {
 | 
			
		||||
            top: 59px;
 | 
			
		||||
            background-color: #CCCCCC;
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          &:after {
 | 
			
		||||
            left: 7px;
 | 
			
		||||
            top: 59px;
 | 
			
		||||
            background-color: #FFFFFF;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .info {
 | 
			
		||||
          & > span:first-child {
 | 
			
		||||
            font-size: 30px;
 | 
			
		||||
            color: #999999;
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          & > span:last-child {
 | 
			
		||||
            font-size: 30px;
 | 
			
		||||
            color: #343D65;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .tag{
 | 
			
		||||
          width: 112px;
 | 
			
		||||
          height: 112px;
 | 
			
		||||
          background-repeat: no-repeat !important;
 | 
			
		||||
          background-size: 100% 100% !important;
 | 
			
		||||
          position: absolute;
 | 
			
		||||
          top: 0;
 | 
			
		||||
          right: 0;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ::v-deep .content{
 | 
			
		||||
      padding: 0 !important;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										358
									
								
								src/pages/notification/components/add.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,358 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="add-meeting">
 | 
			
		||||
    <div v-if="!userSelect">
 | 
			
		||||
      <div class="card">
 | 
			
		||||
        <header><em>*</em>公告标题</header>
 | 
			
		||||
        <input v-model="form.title" placeholder="请输入" :maxlength="30">
 | 
			
		||||
      </div>
 | 
			
		||||
 | 
			
		||||
      <div class="card">
 | 
			
		||||
        <header><em>*</em>公告内容</header>
 | 
			
		||||
        <textarea v-model="form.content" placeholder="请输入" :maxlength="500"></textarea>
 | 
			
		||||
      </div>
 | 
			
		||||
 | 
			
		||||
      <div class="card">
 | 
			
		||||
        <AiUploader :multiple="true" type="image" :limit="9" placeholder="上传图片" @list="fileList" :def="form.files"></AiUploader>
 | 
			
		||||
      </div>
 | 
			
		||||
 | 
			
		||||
      <div class="card item-wrap" @click="select">
 | 
			
		||||
        <u-row justify="between" class="item" style="border-bottom: 1px solid #eeeeee" @click="userSelect=true">
 | 
			
		||||
          <header><em>*</em>发送对象</header>
 | 
			
		||||
          <div class="right">
 | 
			
		||||
            <template v-if="!form.persons.length">
 | 
			
		||||
              <span>请选择</span>
 | 
			
		||||
            </template>
 | 
			
		||||
            <template v-else>
 | 
			
		||||
              已选择<em>{{form.persons.map(e=>e.name).slice(0,2).join("、")}}</em>等<em>{{form.persons.length}}</em>人
 | 
			
		||||
            </template>
 | 
			
		||||
            <div class="right-arrow"></div>
 | 
			
		||||
          </div>
 | 
			
		||||
        </u-row>
 | 
			
		||||
 | 
			
		||||
        <u-row justify="between" class="item" @click="userSelect=true">
 | 
			
		||||
          <header><em>*</em>发送时间</header>
 | 
			
		||||
        </u-row>
 | 
			
		||||
        <u-row justify="between">
 | 
			
		||||
          <div class="type" :class="[index==0 && 'active']" @click="index=0,form.releaseTime=null">立即发送
 | 
			
		||||
            <img :src="$cdn + 'notice/jiaobiao.png'" alt="" v-show="index==0">
 | 
			
		||||
          </div>
 | 
			
		||||
          <div class="type" :class="[index==1 && 'active']"  @click="index=1">定时发送
 | 
			
		||||
            <img :src="$cdn + 'notice/jiaobiao.png'" alt="" v-show="index==1">
 | 
			
		||||
          </div>
 | 
			
		||||
        </u-row>
 | 
			
		||||
        <u-gap height="38"></u-gap>
 | 
			
		||||
        <u-row justify="between" class="item" style="box-shadow: none;" @click="show=true" v-show="index==1">
 | 
			
		||||
          <header><em>*</em>定时发送时间</header>
 | 
			
		||||
          <div class="right">
 | 
			
		||||
            <template v-if="!form.releaseTime">
 | 
			
		||||
              <span>请选择</span>
 | 
			
		||||
            </template>
 | 
			
		||||
            <template v-else>
 | 
			
		||||
              <span>{{form.releaseTime}}</span>
 | 
			
		||||
            </template>
 | 
			
		||||
            <div class="right-arrow"></div>
 | 
			
		||||
          </div>
 | 
			
		||||
        </u-row>
 | 
			
		||||
      </div>
 | 
			
		||||
 | 
			
		||||
      <div class="footer">
 | 
			
		||||
        <div @click="add(0)">保存草稿</div>
 | 
			
		||||
        <div @click="add(1)">立即发布</div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <AiBack ref="aiBack" v-if="!userSelect"/>
 | 
			
		||||
    <u-picker v-model="show" mode="time" :params="params" @confirm="confirm"></u-picker>
 | 
			
		||||
    <AiSelectEnterprise :visible.sync="userSelect" :value="form.persons" v-if="userSelect" @change="change"></AiSelectEnterprise>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
  import AiBack from "../../../components/AiBack";
 | 
			
		||||
  import AiSelectEnterprise from "../../../components/AiSelectEnterprise/AiSelectEnterprise";
 | 
			
		||||
  import AiUploader from "../../../components/AiUploader";
 | 
			
		||||
 | 
			
		||||
  export default {
 | 
			
		||||
    name: "add",
 | 
			
		||||
    components: {AiBack,AiSelectEnterprise,AiUploader},
 | 
			
		||||
    data() {
 | 
			
		||||
      return {
 | 
			
		||||
        show: false,
 | 
			
		||||
        index: 0,
 | 
			
		||||
        list: [],
 | 
			
		||||
        form: {
 | 
			
		||||
          id: null,
 | 
			
		||||
          title: "",
 | 
			
		||||
          content: "",
 | 
			
		||||
          persons: [],
 | 
			
		||||
          releaseTime:null,
 | 
			
		||||
          files: [],
 | 
			
		||||
        },
 | 
			
		||||
        userSelect: false,
 | 
			
		||||
        params: {
 | 
			
		||||
          year: true,
 | 
			
		||||
          month: true,
 | 
			
		||||
          day: true,
 | 
			
		||||
          hour: true,
 | 
			
		||||
          minute: true,
 | 
			
		||||
          second: true,
 | 
			
		||||
          timestamp: true,
 | 
			
		||||
        },
 | 
			
		||||
        flag: null,
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    onLoad(opt) {
 | 
			
		||||
      if(opt.id) {
 | 
			
		||||
        this.form.id = opt.id;
 | 
			
		||||
        this.flag = opt.flag;
 | 
			
		||||
        this.getDetail();
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    methods: {
 | 
			
		||||
      confirm(e){
 | 
			
		||||
        if(e.timestamp< (Date.now()/1000)|0){
 | 
			
		||||
          return this.$u.toast("发送时间不能小于当前时间");
 | 
			
		||||
        }
 | 
			
		||||
        this.form.releaseTime = `${e.year}-${e.month}-${e.day} ${e.hour}:${e.minute}:${e.second}`;
 | 
			
		||||
      },
 | 
			
		||||
      fileList(e){
 | 
			
		||||
        this.form.files = e
 | 
			
		||||
      },
 | 
			
		||||
      change(e){
 | 
			
		||||
        this.form.persons = e
 | 
			
		||||
      },
 | 
			
		||||
      getDetail(){
 | 
			
		||||
        this.$http.post("/app/appannouncement/detail",null,{
 | 
			
		||||
          params:{
 | 
			
		||||
            id:this.form.id,
 | 
			
		||||
            detail: this.flag
 | 
			
		||||
          }
 | 
			
		||||
        }).then(res=>{
 | 
			
		||||
          if (res && res.data) {
 | 
			
		||||
            this.form.releaseTime = res.data.releaseTime;
 | 
			
		||||
            Object.keys(this.form).map(e=>{
 | 
			
		||||
              this.form[e] =  res.data[e];
 | 
			
		||||
            })
 | 
			
		||||
            this.index = res.data.releaseTime ? 1 : 0;
 | 
			
		||||
          }
 | 
			
		||||
        })
 | 
			
		||||
      },
 | 
			
		||||
 | 
			
		||||
      add(status) {
 | 
			
		||||
        if(status==1){
 | 
			
		||||
          if (!this.form.title) return this.$u.toast("请输入会议标题")
 | 
			
		||||
 | 
			
		||||
          if (!this.form.content) return this.$u.toast("请输入会议内容")
 | 
			
		||||
 | 
			
		||||
          if(!this.form.persons.length) return this.$u.toast("请选择发送对象")
 | 
			
		||||
 | 
			
		||||
          if(this.index==1 && !this.form.releaseTime) return this.$u.toast("请选择定时发送时间")
 | 
			
		||||
 | 
			
		||||
          if(this.form.releaseTime && new Date(this.form.releaseTime).getTime() < Date.now()) return this.$u.toast("发送时间不能小于当前时间");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.$http.post("/app/appannouncement/addOrUpdate", {
 | 
			
		||||
          ...this.form,
 | 
			
		||||
          status,
 | 
			
		||||
        }).then(res => {
 | 
			
		||||
          if (res.code == 0) {
 | 
			
		||||
            this.$u.toast(status == 1 ? "发布成功" : "保存成功")
 | 
			
		||||
            this.$refs["aiBack"].back()
 | 
			
		||||
          }
 | 
			
		||||
        })
 | 
			
		||||
      },
 | 
			
		||||
      select() {
 | 
			
		||||
        uni.navigateTo({
 | 
			
		||||
          url: "/pages/meetingNotice/components/notice"
 | 
			
		||||
        })
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    computed:{
 | 
			
		||||
      background(){
 | 
			
		||||
        return `url(${this.$cdn}/notice/jiaobiao.png) no-repeat; background-size: 46px 48px;position: absolute;bottom: 0;right: 0;`
 | 
			
		||||
      },
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
  .add-meeting {
 | 
			
		||||
    min-height: 100%;
 | 
			
		||||
    background: #F5F5F5;
 | 
			
		||||
    padding-bottom: 140px;
 | 
			
		||||
 | 
			
		||||
    .card {
 | 
			
		||||
      background-color: #FFFFFF;
 | 
			
		||||
      box-sizing: border-box;
 | 
			
		||||
      padding: 32px;
 | 
			
		||||
      margin-top: 16px;
 | 
			
		||||
 | 
			
		||||
      header {
 | 
			
		||||
        font-size: 32px;
 | 
			
		||||
        font-weight: 400;
 | 
			
		||||
        color: #333333;
 | 
			
		||||
 | 
			
		||||
        em {
 | 
			
		||||
          font-style: normal;
 | 
			
		||||
          font-size: 32px;
 | 
			
		||||
          color: #FF4466;
 | 
			
		||||
          margin-right: 8px;
 | 
			
		||||
          vertical-align: middle;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      input {
 | 
			
		||||
        margin: 32px 0 16px;
 | 
			
		||||
        box-sizing: border-box;
 | 
			
		||||
        padding: 0 16px;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      textarea {
 | 
			
		||||
        width: 100%;
 | 
			
		||||
        height: 160px;
 | 
			
		||||
        margin: 32px 0 16px;
 | 
			
		||||
        box-sizing: border-box;
 | 
			
		||||
        padding: 0 16px;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .u-row {
 | 
			
		||||
        margin-top: 34px;
 | 
			
		||||
 | 
			
		||||
        .time {
 | 
			
		||||
          display: flex;
 | 
			
		||||
          flex-direction: column;
 | 
			
		||||
 | 
			
		||||
          & > span:first-child {
 | 
			
		||||
            font-size: 60px;
 | 
			
		||||
            font-weight: 600;
 | 
			
		||||
            color: #333333;
 | 
			
		||||
            line-height: 84px;
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          & > span:last-child {
 | 
			
		||||
            font-size: 22px;
 | 
			
		||||
            color: #333333;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .arrow {
 | 
			
		||||
          width: 28px;
 | 
			
		||||
          height: 68px;
 | 
			
		||||
          overflow: hidden;
 | 
			
		||||
          position: relative;
 | 
			
		||||
          transform: rotate(180deg);
 | 
			
		||||
 | 
			
		||||
          &:before, &:after {
 | 
			
		||||
            content: "";
 | 
			
		||||
            width: 50px;
 | 
			
		||||
            height: 50px;
 | 
			
		||||
            position: absolute;
 | 
			
		||||
            transform: scaleY(1.3) translate(30%, -40px) rotate(45deg);
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          &:before {
 | 
			
		||||
            top: 59px;
 | 
			
		||||
            background-color: #CCCCCC;
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          &:after {
 | 
			
		||||
            left: 7px;
 | 
			
		||||
            top: 59px;
 | 
			
		||||
            background-color: #FFFFFF;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .type{
 | 
			
		||||
          width: 320px;
 | 
			
		||||
          height: 112px;
 | 
			
		||||
          background: #F5F5F5;
 | 
			
		||||
          color: #333333;
 | 
			
		||||
          border-radius: 4px;
 | 
			
		||||
          display: flex;
 | 
			
		||||
          align-items: center;
 | 
			
		||||
          justify-content: center;
 | 
			
		||||
          font-size: 30px;
 | 
			
		||||
          font-weight: 500;
 | 
			
		||||
          letter-spacing: 1px;
 | 
			
		||||
          position: relative;
 | 
			
		||||
 | 
			
		||||
          & > img{
 | 
			
		||||
            width: 46px;
 | 
			
		||||
            height: 48px;
 | 
			
		||||
            position: absolute;
 | 
			
		||||
            right: 0;
 | 
			
		||||
            bottom: 0;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
        .active{
 | 
			
		||||
          background-color: #E7F1FE;
 | 
			
		||||
          color: #1174FE;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .item {
 | 
			
		||||
        height: 112px;
 | 
			
		||||
        box-shadow: 0px -1px 0px 0px #D8DDE6;
 | 
			
		||||
        margin-top: 0;
 | 
			
		||||
 | 
			
		||||
        .right {
 | 
			
		||||
          font-size: 28px;
 | 
			
		||||
          color: #999999;
 | 
			
		||||
          display: flex;
 | 
			
		||||
          align-items: center;
 | 
			
		||||
 | 
			
		||||
          em {
 | 
			
		||||
            font-style: normal;
 | 
			
		||||
            color: #1365DD;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .right-arrow {
 | 
			
		||||
          width: 16px;
 | 
			
		||||
          height: 16px;
 | 
			
		||||
          display: inline-block;
 | 
			
		||||
          border-top: 5px solid #CCCCCC;
 | 
			
		||||
          border-right: 5px solid #CCCCCC;
 | 
			
		||||
          transform: rotate(45deg);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .item-wrap {
 | 
			
		||||
      padding: 0 32px;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .footer {
 | 
			
		||||
      height: 112px;
 | 
			
		||||
      width: 100%;
 | 
			
		||||
      position: fixed;
 | 
			
		||||
      left: 0;
 | 
			
		||||
      bottom: 0;
 | 
			
		||||
      background-color: #FFFFFF;
 | 
			
		||||
      display: flex;
 | 
			
		||||
      align-items: center;
 | 
			
		||||
 | 
			
		||||
      & > div {
 | 
			
		||||
        font-size: 36px;
 | 
			
		||||
        color: #333333;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      & > div:first-child {
 | 
			
		||||
        width: 270px;
 | 
			
		||||
        height: 100%;
 | 
			
		||||
        display: flex;
 | 
			
		||||
        align-items: center;
 | 
			
		||||
        justify-content: center;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      & > div:last-child {
 | 
			
		||||
        width: calc(100% - 270px);
 | 
			
		||||
        height: 100%;
 | 
			
		||||
        color: #FFFFFF;
 | 
			
		||||
        display: flex;
 | 
			
		||||
        align-items: center;
 | 
			
		||||
        justify-content: center;
 | 
			
		||||
        background-color: #1365DD;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										345
									
								
								src/pages/notification/components/detail.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,345 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="detail">
 | 
			
		||||
    <template v-if="detailObj">
 | 
			
		||||
      <div class="card">
 | 
			
		||||
        <header>{{detailObj.title}}</header>
 | 
			
		||||
        <u-gap height="16"></u-gap>
 | 
			
		||||
        <u-row>
 | 
			
		||||
          <span>发布人:</span>
 | 
			
		||||
          <span>{{detailObj.releaseUserName}}</span>
 | 
			
		||||
        </u-row>
 | 
			
		||||
        <u-gap height="8"></u-gap>
 | 
			
		||||
        <u-row>
 | 
			
		||||
          <span>发布部门:</span>
 | 
			
		||||
          <span>{{detailObj.unitName}}</span>
 | 
			
		||||
        </u-row>
 | 
			
		||||
        <u-gap height="8"></u-gap>
 | 
			
		||||
        <u-row>
 | 
			
		||||
          <span>发布日期:</span>
 | 
			
		||||
          <span>{{detailObj.releaseTime}}</span>
 | 
			
		||||
        </u-row>
 | 
			
		||||
        <u-gap height="8"></u-gap>
 | 
			
		||||
      </div>
 | 
			
		||||
 | 
			
		||||
      <div class="card">
 | 
			
		||||
        <div class="label">公告内容</div>
 | 
			
		||||
        <u-parse :html="detailObj.content"></u-parse>
 | 
			
		||||
      </div>
 | 
			
		||||
 | 
			
		||||
      <div class="card" style="padding-top: 0" v-if="detailObj.files && detailObj.files.length">
 | 
			
		||||
        <div class="label">相关附件</div>
 | 
			
		||||
        <div class="file" v-for="(item,index) in detailObj.files" :key="index" @click="preFile(item)">
 | 
			
		||||
          <u-row justify="between">
 | 
			
		||||
            <label class="left">
 | 
			
		||||
              <img :src="$cdn + 'common/appendix.png'" alt="">
 | 
			
		||||
              <span>{{item.name}}.{{item.postfix}}</span>
 | 
			
		||||
            </label>
 | 
			
		||||
            <span>{{(item.size/1024).toFixed(2)}}KB</span>
 | 
			
		||||
          </u-row>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
 | 
			
		||||
      <div class="card" @click="handleClick">
 | 
			
		||||
        <u-row justify="between" class="item">
 | 
			
		||||
          <span>接收对象</span>
 | 
			
		||||
          <div class="right">
 | 
			
		||||
            <em>{{detailObj.readNum}}人</em>已读
 | 
			
		||||
            <em>{{detailObj.unReadNum}}人</em>未读
 | 
			
		||||
            <div class="arrow"></div>
 | 
			
		||||
          </div>
 | 
			
		||||
        </u-row>
 | 
			
		||||
      </div>
 | 
			
		||||
    </template>
 | 
			
		||||
    <AiEmpty description="该通知已撤回" v-else/>
 | 
			
		||||
    <AiBack />
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
  import AiBack from "../../../components/AiBack";
 | 
			
		||||
  import {mapActions} from "vuex";
 | 
			
		||||
  import AiEmpty from "../../../components/AiEmpty/AiEmpty";
 | 
			
		||||
 | 
			
		||||
  export default {
 | 
			
		||||
    name: "detail",
 | 
			
		||||
    components:{AiBack,AiEmpty},
 | 
			
		||||
    data() {
 | 
			
		||||
      return {
 | 
			
		||||
        detailObj: null,
 | 
			
		||||
        id: null,
 | 
			
		||||
        flag: null,
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    onLoad(opt){
 | 
			
		||||
      this.id = opt.id;
 | 
			
		||||
      this.flag = opt.flag;
 | 
			
		||||
      this.getDetail();
 | 
			
		||||
    },
 | 
			
		||||
    methods: {
 | 
			
		||||
      ...mapActions(['previewFile', 'injectJWeixin']),
 | 
			
		||||
      preFile(e) {
 | 
			
		||||
        if([".jpg",".png",".gif"].includes(e.postfix.toLowerCase())){
 | 
			
		||||
          uni.previewImage({
 | 
			
		||||
            current: e.url,
 | 
			
		||||
            urls: [e.url]
 | 
			
		||||
          })
 | 
			
		||||
        }else {
 | 
			
		||||
          this.previewFile({...e})
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      getDetail() {
 | 
			
		||||
        this.$http.post("/app/appannouncement/detail", null, {
 | 
			
		||||
          params: {
 | 
			
		||||
            id: this.id,
 | 
			
		||||
            detail: this.flag
 | 
			
		||||
          }
 | 
			
		||||
        }).then(res=>{
 | 
			
		||||
          if(res && res.data){
 | 
			
		||||
            this.detailObj = res.data;
 | 
			
		||||
          }
 | 
			
		||||
        })
 | 
			
		||||
      },
 | 
			
		||||
      handleClick() {
 | 
			
		||||
        uni.navigateTo({
 | 
			
		||||
          url:"/pages/notification/components/read?id=" + this.id,
 | 
			
		||||
        })
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
  }
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
  .detail {
 | 
			
		||||
    min-height: 100%;
 | 
			
		||||
    background-color: #F5F5F5;
 | 
			
		||||
    padding-bottom: 140px;
 | 
			
		||||
 | 
			
		||||
    ::v-deep .content {
 | 
			
		||||
      padding: 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .card {
 | 
			
		||||
      background-color: #FFFFFF;
 | 
			
		||||
      margin-bottom: 8px;
 | 
			
		||||
      box-sizing: border-box;
 | 
			
		||||
      padding: 16px 32px;
 | 
			
		||||
 | 
			
		||||
      header {
 | 
			
		||||
        font-size: 40px;
 | 
			
		||||
        font-weight: 600;
 | 
			
		||||
        color: #333333;
 | 
			
		||||
        line-height: 64px;
 | 
			
		||||
        letter-spacing: 1px;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .u-row {
 | 
			
		||||
        & > div {
 | 
			
		||||
          border-radius: 50%;
 | 
			
		||||
          text-align: center;
 | 
			
		||||
          font-size: 22px;
 | 
			
		||||
          font-weight: bold;
 | 
			
		||||
          color: #FFFFFF;
 | 
			
		||||
          display: flex;
 | 
			
		||||
          align-items: center;
 | 
			
		||||
          justify-content: center;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        & > span:first-child {
 | 
			
		||||
          font-size: 30px;
 | 
			
		||||
          color: #999999;;
 | 
			
		||||
          line-height: 48px;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        & > span:last-child {
 | 
			
		||||
          font-size: 30px;
 | 
			
		||||
          color: #343D65;
 | 
			
		||||
          margin-left: 16px;
 | 
			
		||||
          line-height: 48px;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .title {
 | 
			
		||||
          width: 490px;
 | 
			
		||||
          height: 112px;
 | 
			
		||||
          display: flex;
 | 
			
		||||
          align-items: center;
 | 
			
		||||
          font-size: 32px;
 | 
			
		||||
          color: #333333;
 | 
			
		||||
          overflow: hidden;
 | 
			
		||||
          text-overflow: ellipsis;
 | 
			
		||||
          white-space: nowrap;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .right {
 | 
			
		||||
          font-size: 28px;
 | 
			
		||||
          display: flex;
 | 
			
		||||
          align-items: center;
 | 
			
		||||
          color: #666666;
 | 
			
		||||
 | 
			
		||||
          .arrow {
 | 
			
		||||
            width: 16px;
 | 
			
		||||
            height: 16px;
 | 
			
		||||
            border-top: 3px solid #CCCCCC;
 | 
			
		||||
            border-right: 3px solid #CCCCCC;
 | 
			
		||||
            transform: rotate(45deg);
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .item {
 | 
			
		||||
        position: relative;
 | 
			
		||||
        height: 80px;
 | 
			
		||||
 | 
			
		||||
        &:after {
 | 
			
		||||
          width: 100%;
 | 
			
		||||
          height: 1px;
 | 
			
		||||
          background-color: rgba(216, 221, 230, 0.5);
 | 
			
		||||
          content: "";
 | 
			
		||||
          position: absolute;
 | 
			
		||||
          left: 0;
 | 
			
		||||
          bottom: 0;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      & > span {
 | 
			
		||||
        font-size: 32px;
 | 
			
		||||
        color: #333333;
 | 
			
		||||
        line-height: 48px;
 | 
			
		||||
        letter-spacing: 1px;
 | 
			
		||||
        display: inline-block;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .label {
 | 
			
		||||
        height: 80px;
 | 
			
		||||
        font-size: 32px;
 | 
			
		||||
        color: #333333;
 | 
			
		||||
        display: flex;
 | 
			
		||||
        align-items: center;
 | 
			
		||||
        margin-bottom: 16px;
 | 
			
		||||
 | 
			
		||||
        & > em {
 | 
			
		||||
          font-style: normal;
 | 
			
		||||
          font-size: 32px;
 | 
			
		||||
          color: #1365DD;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .file {
 | 
			
		||||
        height: 128px;
 | 
			
		||||
        background: #FFFFFF;
 | 
			
		||||
        border-radius: 8px;
 | 
			
		||||
        border: 1px solid #CCCCCC;
 | 
			
		||||
        box-sizing: border-box;
 | 
			
		||||
        padding: 0 16px;
 | 
			
		||||
        margin-bottom: 32px;
 | 
			
		||||
 | 
			
		||||
        & > .u-row {
 | 
			
		||||
          height: 100%;
 | 
			
		||||
 | 
			
		||||
          .left {
 | 
			
		||||
            width: 476px;
 | 
			
		||||
            display: flex;
 | 
			
		||||
            align-items: center;
 | 
			
		||||
 | 
			
		||||
            & > img {
 | 
			
		||||
              flex-shrink: 0;
 | 
			
		||||
              width: 96px;
 | 
			
		||||
              height: 96px;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            & > span {
 | 
			
		||||
              font-size: 32px;
 | 
			
		||||
              color: #333333;
 | 
			
		||||
              display: inline-block;
 | 
			
		||||
              line-height: 44px;
 | 
			
		||||
              overflow: hidden;
 | 
			
		||||
              text-overflow: ellipsis;
 | 
			
		||||
              display: -webkit-box;
 | 
			
		||||
              -webkit-box-orient: vertical;
 | 
			
		||||
              -webkit-line-clamp: 2;
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          & > span {
 | 
			
		||||
            font-size: 28px;
 | 
			
		||||
            color: #999999;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .active {
 | 
			
		||||
        background-color: #F3F6F9;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      & > text {
 | 
			
		||||
        width: 100%;
 | 
			
		||||
        display: inline-block;
 | 
			
		||||
        font-size: 30px;
 | 
			
		||||
        color: #649EFD;
 | 
			
		||||
        text-align: center;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .progress {
 | 
			
		||||
        height: 12px;
 | 
			
		||||
        background: #F2F4FC;
 | 
			
		||||
        border-radius: 12px;
 | 
			
		||||
        position: relative;
 | 
			
		||||
        margin: 16px 0 64px 0;
 | 
			
		||||
 | 
			
		||||
        .pro-active {
 | 
			
		||||
          height: 12px;
 | 
			
		||||
          background: #639EFD;
 | 
			
		||||
          border-radius: 12px;
 | 
			
		||||
          position: absolute;
 | 
			
		||||
          left: 0;
 | 
			
		||||
          top: 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      em {
 | 
			
		||||
        font-style: normal;
 | 
			
		||||
        font-size: 28px;
 | 
			
		||||
        color: #1365DD;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      ::v-deep .u-collapse {
 | 
			
		||||
        position: relative;
 | 
			
		||||
 | 
			
		||||
        &:after {
 | 
			
		||||
          content: "";
 | 
			
		||||
          width: 718px;
 | 
			
		||||
          height: 1px;
 | 
			
		||||
          background-color: rgba(216, 221, 230, 0.5);
 | 
			
		||||
          position: absolute;
 | 
			
		||||
          left: 0;
 | 
			
		||||
          bottom: 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .u-collapse-head {
 | 
			
		||||
          padding: 40px 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .u-collapse-content {
 | 
			
		||||
          font-size: 32px;
 | 
			
		||||
          color: #333333;
 | 
			
		||||
          line-height: 48px;
 | 
			
		||||
          letter-spacing: 1px;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .footer {
 | 
			
		||||
      height: 112px;
 | 
			
		||||
      width: 100%;
 | 
			
		||||
      position: fixed;
 | 
			
		||||
      left: 0;
 | 
			
		||||
      bottom: 0;
 | 
			
		||||
      background: #1365DD;
 | 
			
		||||
      display: flex;
 | 
			
		||||
      align-items: center;
 | 
			
		||||
      justify-content: center;
 | 
			
		||||
      font-size: 36px;
 | 
			
		||||
      color: #FFFFFF;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										93
									
								
								src/pages/notification/components/read.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,93 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="read">
 | 
			
		||||
    <AiTopFixed>
 | 
			
		||||
      <u-tabs :list="tabs" :is-scroll="false" height="96" bar-width="192" :current="current" @change="change"></u-tabs>
 | 
			
		||||
    </AiTopFixed>
 | 
			
		||||
    <div class="body">
 | 
			
		||||
      <div class="item" v-for="(item,index) in (current==0 ? list.read : list.unRead)" :key="index">
 | 
			
		||||
        <u-avatar :src="item.avatar" mode="square" size="76"></u-avatar>
 | 
			
		||||
        <span class="name">{{item.name}}</span>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <AiBack/>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
  import AiBack from "../../../components/AiBack";
 | 
			
		||||
  import AiTopFixed from "../../../components/AiTopFixed";
 | 
			
		||||
 | 
			
		||||
  export default {
 | 
			
		||||
    name: "read",
 | 
			
		||||
    components: {AiBack, AiTopFixed},
 | 
			
		||||
    data() {
 | 
			
		||||
      return {
 | 
			
		||||
        current: 0,
 | 
			
		||||
        id: null,
 | 
			
		||||
        list: [],
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    onLoad(opt) {
 | 
			
		||||
      this.id = opt.id;
 | 
			
		||||
      this.getList();
 | 
			
		||||
    },
 | 
			
		||||
    methods: {
 | 
			
		||||
      getList() {
 | 
			
		||||
        this.$http.post("/app/appannouncementreader/list-unread",null,{
 | 
			
		||||
          params:{
 | 
			
		||||
            id:this.id
 | 
			
		||||
          }
 | 
			
		||||
        }).then(res => {
 | 
			
		||||
          if (res && res.data) {
 | 
			
		||||
            this.list = res.data;
 | 
			
		||||
          }
 | 
			
		||||
        })
 | 
			
		||||
      },
 | 
			
		||||
      change(val) {
 | 
			
		||||
        this.current = val;
 | 
			
		||||
        this.getList();
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    computed: {
 | 
			
		||||
      tabs() {
 | 
			
		||||
        return [
 | 
			
		||||
          {name: this.list?.read?.length + "人已读"},
 | 
			
		||||
          {name: this.list?.unRead?.length + "人未读"},
 | 
			
		||||
        ];
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
  }
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
  .read {
 | 
			
		||||
    min-height: 100%;
 | 
			
		||||
    background-color: #F5F5F5;
 | 
			
		||||
 | 
			
		||||
    ::v-deep .content{
 | 
			
		||||
      padding: 0 !important;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .body {
 | 
			
		||||
      padding: 16px 0;
 | 
			
		||||
 | 
			
		||||
     .item {
 | 
			
		||||
        height: 120px;
 | 
			
		||||
        display: flex;
 | 
			
		||||
       align-items: center;
 | 
			
		||||
        box-sizing: border-box;
 | 
			
		||||
        padding: 0 50px;
 | 
			
		||||
        background-color: #ffffff;
 | 
			
		||||
        border-bottom: 1px solid #eeeeee;
 | 
			
		||||
 | 
			
		||||
        & > .name{
 | 
			
		||||
          font-size: 36px;
 | 
			
		||||
          font-weight: 600;
 | 
			
		||||
          color: #333333;
 | 
			
		||||
          line-height: 50px;
 | 
			
		||||
          margin-left: 32px;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										354
									
								
								src/pages/notification/notification.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,354 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="notification">
 | 
			
		||||
    <AiTopFixed>
 | 
			
		||||
      <u-tabs :list="tabs" :is-scroll="false" height="96" bar-width="192" :current="index" @change="change"></u-tabs>
 | 
			
		||||
    </AiTopFixed>
 | 
			
		||||
    <div class="body" v-if="dataList.length">
 | 
			
		||||
      <div class="card" v-for="(item,idx) in dataList" :key="idx" @click="handeClick(item)">
 | 
			
		||||
        <template v-if="!item.imgUrl">
 | 
			
		||||
          <label>
 | 
			
		||||
            <b v-if="index==0 && item.readStatus==0"></b>
 | 
			
		||||
            <div class="tag" v-if="index==1" :style="color(item.status)">{{$dict.getLabel("announcementStatus",item.status)}}</div>
 | 
			
		||||
            {{item.title}}
 | 
			
		||||
          </label>
 | 
			
		||||
          <u-gap height="16"></u-gap>
 | 
			
		||||
          <span class="info">
 | 
			
		||||
            <text>{{item.releaseUserName}}</text>
 | 
			
		||||
            <text>{{item.releaseTime}}</text>
 | 
			
		||||
          </span>
 | 
			
		||||
        </template>
 | 
			
		||||
        <template v-else>
 | 
			
		||||
          <div class="has-pic">
 | 
			
		||||
            <div class="left">
 | 
			
		||||
              <label>
 | 
			
		||||
                <b v-if="index==0 && item.readStatus==0"></b>
 | 
			
		||||
                <div class="tag" v-if="index==1" :style="color(item.status)">{{$dict.getLabel("announcementStatus",item.status)}}</div>
 | 
			
		||||
                {{item.title}}
 | 
			
		||||
              </label>
 | 
			
		||||
              <u-gap height="16"></u-gap>
 | 
			
		||||
              <span class="info">
 | 
			
		||||
                <text>{{item.releaseUserName}}</text>
 | 
			
		||||
                <text>{{item.releaseTime}}</text>
 | 
			
		||||
              </span>
 | 
			
		||||
            </div>
 | 
			
		||||
            <img :src="item.imgUrl" alt="">
 | 
			
		||||
          </div>
 | 
			
		||||
        </template>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <AiEmpty v-else/>
 | 
			
		||||
    <u-loadmore :status="status" v-if="dataList.length"/>
 | 
			
		||||
    <AiAdd @add="add"/>
 | 
			
		||||
    <u-popup v-model="show" mode="bottom">
 | 
			
		||||
      <div class="popup-wrap">
 | 
			
		||||
        <u-row justify="between">
 | 
			
		||||
          <div class="colum" v-for="(item,index) in optList" :key="index" @click="handleOpt(item)">
 | 
			
		||||
            <u-icon :name="item.icon" size="100" :custom-style="{backgroundColor:'#fff',borderRadius:'16px'}"></u-icon>
 | 
			
		||||
            <u-gap height="16"></u-gap>
 | 
			
		||||
            {{item.name}}
 | 
			
		||||
          </div>
 | 
			
		||||
        </u-row>
 | 
			
		||||
        <div class="btn" @click="show=false">关闭</div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </u-popup>
 | 
			
		||||
    <u-modal v-model="modal" :content="'是否确定' + content + '该公告?'" title="" show-confirm-button
 | 
			
		||||
             show-cancel-button confirm-text="确定" cancel-text="取消"
 | 
			
		||||
             @confirm="confirm"></u-modal>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
  import AiAdd from "../../components/AiAdd";
 | 
			
		||||
  import AiEmpty from "../../components/AiEmpty/AiEmpty";
 | 
			
		||||
  import AiTopFixed from "../../components/AiTopFixed";
 | 
			
		||||
 | 
			
		||||
  export default {
 | 
			
		||||
    name: "notification",
 | 
			
		||||
    components: {AiAdd, AiEmpty,AiTopFixed},
 | 
			
		||||
    data() {
 | 
			
		||||
      return {
 | 
			
		||||
        index: 0,
 | 
			
		||||
        show: false,
 | 
			
		||||
        modal: false,
 | 
			
		||||
        content: "",
 | 
			
		||||
        current: 1,
 | 
			
		||||
        dataList: [],
 | 
			
		||||
        detail: {},
 | 
			
		||||
        status: "加载更多",
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    onLoad(){
 | 
			
		||||
      this.$dict.load("announcementStatus");
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    computed: {
 | 
			
		||||
      tabs() {
 | 
			
		||||
        return [{name: "最新公告"},{name: "公告管理"}];
 | 
			
		||||
      },
 | 
			
		||||
      optList(){
 | 
			
		||||
        return [
 | 
			
		||||
          {
 | 
			
		||||
            name: "详情",
 | 
			
		||||
            icon: this.$cdn + "notice/yl.png",
 | 
			
		||||
            val: 0,
 | 
			
		||||
            show: true,
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            name: "撤回",
 | 
			
		||||
            icon: this.$cdn + "notice/ch.png",
 | 
			
		||||
            val: 1,
 | 
			
		||||
            show: this.detail?.status == 1,
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            name: "发布",
 | 
			
		||||
            icon: this.$cdn + "notice/fb.png",
 | 
			
		||||
            val: 2,
 | 
			
		||||
            show: this.detail?.status == 0,
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            name: "编辑",
 | 
			
		||||
            icon: this.$cdn + "notice/bj.png",
 | 
			
		||||
            val: 3,
 | 
			
		||||
            show: this.detail?.status == 0 || this.detail?.status == 3,
 | 
			
		||||
          }, {
 | 
			
		||||
            name: "删除",
 | 
			
		||||
            icon: this.$cdn + "notice/sc.png",
 | 
			
		||||
            val: 4,
 | 
			
		||||
            show: true,
 | 
			
		||||
          }
 | 
			
		||||
        ].filter(e=>e.show)
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    methods: {
 | 
			
		||||
      changeState(){
 | 
			
		||||
        this.$http.post(this.content =='删除' ? '/app/appannouncement/delete' : "/app/appannouncement/update-status",null,{
 | 
			
		||||
          params: {
 | 
			
		||||
            [this.content =='删除' ? 'ids' : 'id']:this.detail.id
 | 
			
		||||
          }
 | 
			
		||||
        }).then(res=>{
 | 
			
		||||
          if(res.code==0){
 | 
			
		||||
            this.$u.toast(this.content + "成功");
 | 
			
		||||
            this.getList();
 | 
			
		||||
          }
 | 
			
		||||
        })
 | 
			
		||||
      },
 | 
			
		||||
      confirm(){
 | 
			
		||||
        this.show = false;
 | 
			
		||||
        this.changeState();
 | 
			
		||||
      },
 | 
			
		||||
      handleOpt(item){
 | 
			
		||||
        this.content = {
 | 
			
		||||
          1: "撤回",
 | 
			
		||||
          2: "发布",
 | 
			
		||||
          4: "删除",
 | 
			
		||||
        }[item.val];
 | 
			
		||||
 | 
			
		||||
        if (item.val == 0) {
 | 
			
		||||
          this.show = false;
 | 
			
		||||
          return uni.navigateTo({
 | 
			
		||||
            url: "/pages/notification/components/detail?id=" + this.detail.id
 | 
			
		||||
          });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if ([1,2,4].includes(item.val)) {
 | 
			
		||||
          return this.modal = true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if(item.val==3){
 | 
			
		||||
          this.show = false;
 | 
			
		||||
          return uni.navigateTo({
 | 
			
		||||
            url:"/pages/notification/components/add?id=" + this.detail.id + "&flag=" + false
 | 
			
		||||
          });
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      color(status){
 | 
			
		||||
        return [
 | 
			
		||||
          {backgroundColor:"rgba(255,136,34,0.1)",color:"#FF8822"},
 | 
			
		||||
          {backgroundColor:"rgba(34,102,255,0.1)",color:"#2266FF"},
 | 
			
		||||
          {backgroundColor:"rgba(102,102,102,0.1)",color:"#666666"},
 | 
			
		||||
          {backgroundColor:"rgba(255,136,34,0.1)",color:"#FF8822"}
 | 
			
		||||
          ][status];
 | 
			
		||||
      },
 | 
			
		||||
      handeClick(item) {
 | 
			
		||||
        this.detail = item;
 | 
			
		||||
        if (this.index == 1) {
 | 
			
		||||
          this.show = true;
 | 
			
		||||
        }else {
 | 
			
		||||
          uni.navigateTo({
 | 
			
		||||
            url: "/pages/notification/components/detail?id=" + this.detail.id + "&flag=" + true
 | 
			
		||||
          })
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      add(){
 | 
			
		||||
        uni.navigateTo({
 | 
			
		||||
          url: "/pages/notification/components/add"
 | 
			
		||||
        })
 | 
			
		||||
      },
 | 
			
		||||
      change(val) {
 | 
			
		||||
        this.index = val;
 | 
			
		||||
        this.current = 1;
 | 
			
		||||
        this.getList()
 | 
			
		||||
      },
 | 
			
		||||
      getList() {
 | 
			
		||||
        this.$http.post(this.index ==0 ? "/app/appannouncement/list-latest" : "/app/appannouncement/list-mgr", null, {
 | 
			
		||||
          params: {
 | 
			
		||||
            size: 10,
 | 
			
		||||
            current: this.current
 | 
			
		||||
          }
 | 
			
		||||
        }).then(res => {
 | 
			
		||||
          if (res && res.data) {
 | 
			
		||||
            if (this.current > 1 && this.current > res.data.pages) {
 | 
			
		||||
              this.status = "已经到底啦"
 | 
			
		||||
            }
 | 
			
		||||
            this.dataList = this.current > 1 ? [...this.dataList, ...res.data.records] : res.data.records
 | 
			
		||||
          }
 | 
			
		||||
        })
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    onShow() {
 | 
			
		||||
      this.current = 1;
 | 
			
		||||
      this.getList();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    onReachBottom() {
 | 
			
		||||
      this.current = this.current + 1;
 | 
			
		||||
      this.getList()
 | 
			
		||||
    },
 | 
			
		||||
  }
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
  .notification {
 | 
			
		||||
    min-height: 100%;
 | 
			
		||||
    background-color: #F5F5F5;
 | 
			
		||||
    padding-bottom: 32px;
 | 
			
		||||
 | 
			
		||||
    ::v-deep .content{
 | 
			
		||||
      padding: 0 !important;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .body {
 | 
			
		||||
      box-sizing: border-box;
 | 
			
		||||
      padding: 32px;
 | 
			
		||||
 | 
			
		||||
      .card {
 | 
			
		||||
        height: 208px;
 | 
			
		||||
        display: flex;
 | 
			
		||||
        flex-direction: column;
 | 
			
		||||
        justify-content: space-between;
 | 
			
		||||
        box-sizing: border-box;
 | 
			
		||||
        padding: 32px;
 | 
			
		||||
        border-radius: 8px;
 | 
			
		||||
        background-color: #ffffff;
 | 
			
		||||
        margin-bottom: 32px;
 | 
			
		||||
 | 
			
		||||
        &:last-child{
 | 
			
		||||
          margin-bottom: 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        & > label {
 | 
			
		||||
          font-size: 32px;
 | 
			
		||||
          overflow: hidden;
 | 
			
		||||
          text-overflow: ellipsis;
 | 
			
		||||
          display: -webkit-box;
 | 
			
		||||
          -webkit-box-orient: vertical;
 | 
			
		||||
          -webkit-line-clamp: 2;
 | 
			
		||||
          color: #333333;
 | 
			
		||||
          line-height: 44px;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        b {
 | 
			
		||||
          display: inline-block;
 | 
			
		||||
          font-style: normal;
 | 
			
		||||
          width: 16px;
 | 
			
		||||
          height: 16px;
 | 
			
		||||
          border-radius: 50%;
 | 
			
		||||
          background: #FF4466;
 | 
			
		||||
          margin-right: 8px;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .tag{
 | 
			
		||||
          width: 96px;
 | 
			
		||||
          height: 44px;
 | 
			
		||||
          display: inline-block;
 | 
			
		||||
          border-radius: 8px;
 | 
			
		||||
          margin-right: 16px;
 | 
			
		||||
          font-size: 26px;
 | 
			
		||||
          font-weight: 400;
 | 
			
		||||
          line-height: 46px;
 | 
			
		||||
          text-align: center;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .info {
 | 
			
		||||
          font-size: 28px;
 | 
			
		||||
          color: #999999;
 | 
			
		||||
          line-height: 40px;
 | 
			
		||||
 | 
			
		||||
          & > text:first-child {
 | 
			
		||||
            margin-right: 32px;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        & > .has-pic {
 | 
			
		||||
          display: flex;
 | 
			
		||||
          justify-content: space-between;
 | 
			
		||||
 | 
			
		||||
          & > .left {
 | 
			
		||||
            display: flex;
 | 
			
		||||
            flex-direction: column;
 | 
			
		||||
            justify-content: space-between;
 | 
			
		||||
 | 
			
		||||
            & > label {
 | 
			
		||||
              overflow: hidden;
 | 
			
		||||
              text-overflow: ellipsis;
 | 
			
		||||
              display: -webkit-box;
 | 
			
		||||
              -webkit-box-orient: vertical;
 | 
			
		||||
              -webkit-line-clamp: 2;
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
          & > img{
 | 
			
		||||
            width: 192px;
 | 
			
		||||
            height: 144px;
 | 
			
		||||
            flex-shrink: 0;
 | 
			
		||||
            margin-left: 32px;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .popup-wrap {
 | 
			
		||||
      height: 368px;
 | 
			
		||||
      background-color: #F7F7F7;
 | 
			
		||||
 | 
			
		||||
      .btn{
 | 
			
		||||
        height: 96px;
 | 
			
		||||
        display: flex;
 | 
			
		||||
        align-items: center;
 | 
			
		||||
        justify-content: center;
 | 
			
		||||
        font-size: 30px;
 | 
			
		||||
        font-weight: 500;
 | 
			
		||||
        color: #333333;
 | 
			
		||||
        background-color: #ffffff;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      & > .u-row {
 | 
			
		||||
        height: 272px;
 | 
			
		||||
        box-sizing: border-box;
 | 
			
		||||
        padding: 0 46px;
 | 
			
		||||
 | 
			
		||||
        & > .colum {
 | 
			
		||||
          display: flex;
 | 
			
		||||
          flex-direction: column;
 | 
			
		||||
          align-items: center;
 | 
			
		||||
          justify-content: center;
 | 
			
		||||
          font-size: 26px;
 | 
			
		||||
          color: #666666;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										326
									
								
								src/pages/quickReply/quickReply.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,326 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <section class="quickReply">
 | 
			
		||||
    <ai-top-fixed background="#F5F5F5">
 | 
			
		||||
      <u-tabs slot="tabs" :list="tabs" :is-scroll="false" :current="currentType" font-size="32"
 | 
			
		||||
              bar-width="192" height="96" @change="handleTabClick"/>
 | 
			
		||||
      <u-search placeholder="搜索" shape="square" bg-color="#fff" :show-action="false" search-icon-color="#ccc"
 | 
			
		||||
                v-model="search.title" @search="page.current=1,getList()"/>
 | 
			
		||||
      <ai-tabs v-model="search.category" :ops="categories" @change="getList" wrap>
 | 
			
		||||
        <u-icon v-if="isPersonal" label="管理" size="38" class="manage" name="iconEdit" custom-prefix="iconfont"
 | 
			
		||||
                color="#1365DD" slot="end"
 | 
			
		||||
                label-color="#1365DD" @tap="handleManageType"/>
 | 
			
		||||
      </ai-tabs>
 | 
			
		||||
    </ai-top-fixed>
 | 
			
		||||
    <div class="mainPanel">
 | 
			
		||||
      <div class="fill">
 | 
			
		||||
        <ai-card :card-title="e.title" v-for="(e,i) in list" :key="i" @send="handleSendMsg(e)">
 | 
			
		||||
          <div class="textContent" v-if="e.contentType=='text'" v-html="e.content"/>
 | 
			
		||||
          <div class="fileContent" v-else-if="e.contentType=='news'">
 | 
			
		||||
            <ai-image link/>
 | 
			
		||||
            <div class="info">
 | 
			
		||||
              <span>{{ e.accessTitle }}</span>
 | 
			
		||||
              <em>{{ e.accessUrl }}</em>
 | 
			
		||||
            </div>
 | 
			
		||||
          </div>
 | 
			
		||||
          <div class="fileContent" v-else-if="e.contentType=='miniprogram'">
 | 
			
		||||
            <ai-image miniapp/>
 | 
			
		||||
            <div class="info">
 | 
			
		||||
              {{ e.accessTitle }}
 | 
			
		||||
            </div>
 | 
			
		||||
          </div>
 | 
			
		||||
          <div class="fileContent" v-else>
 | 
			
		||||
            <template v-if="e.file">
 | 
			
		||||
              <ai-image :src="e.file.url"/>
 | 
			
		||||
              <div class="info">
 | 
			
		||||
                <span>{{ e.file.name }}</span>
 | 
			
		||||
                <em>{{ e.file.fileSizeStr }}</em>
 | 
			
		||||
              </div>
 | 
			
		||||
            </template>
 | 
			
		||||
          </div>
 | 
			
		||||
          <template #title>
 | 
			
		||||
            <u-row>
 | 
			
		||||
              <div class="top" v-if="e.isTop==1">置顶</div>
 | 
			
		||||
              <div class="fill">{{ e.title }}</div>
 | 
			
		||||
            </u-row>
 | 
			
		||||
          </template>
 | 
			
		||||
          <template v-if="isPersonal" #menu>
 | 
			
		||||
            <div class="menu" @tap="handleTop(e)">{{ e.isTop == 1 ? '取消' : '' }}置顶</div>
 | 
			
		||||
            <div class="menu" @tap="handleDetail(e.id)">编辑</div>
 | 
			
		||||
            <div class="menu" @tap="handleDel(e.id)">删除</div>
 | 
			
		||||
          </template>
 | 
			
		||||
        </ai-card>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div v-if="isPersonal" class="iconfont iconfont-iconAdd addBtn" @tap="handleDetail('')"/>
 | 
			
		||||
  </section>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import AiTabs from "../../components/AiTabs";
 | 
			
		||||
import AiCard from "../../components/AiCard";
 | 
			
		||||
import {mapActions, mapState} from "vuex";
 | 
			
		||||
import AiImage from "../../components/AiImage";
 | 
			
		||||
import USticky from "../../uview/components/u-sticky/u-sticky";
 | 
			
		||||
import AiTopFixed from "../../components/AiTopFixed";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: "quickReply",
 | 
			
		||||
  components: {AiTopFixed, USticky, AiImage, AiCard, AiTabs},
 | 
			
		||||
  computed: {
 | 
			
		||||
    ...mapState(['agentConfig']),
 | 
			
		||||
    tabs() {
 | 
			
		||||
      return [
 | 
			
		||||
        {name: "个人话术", value: 0},
 | 
			
		||||
        {name: "公共话术", value: 1},
 | 
			
		||||
      ]
 | 
			
		||||
    },
 | 
			
		||||
    categories() {
 | 
			
		||||
      let meta = [{name: "全部分类", value: ""}]
 | 
			
		||||
      this.originCategories.map(e => {
 | 
			
		||||
        if (e.type == this.currentType) {
 | 
			
		||||
          meta.push({name: e.name, value: e.id})
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
      return meta
 | 
			
		||||
    },
 | 
			
		||||
    isPersonal() {
 | 
			
		||||
      return this.currentType == 0
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  data() {
 | 
			
		||||
    return {
 | 
			
		||||
      currentType: 0,
 | 
			
		||||
      page: {current: 1, size: 10, total: 0},
 | 
			
		||||
      list: [],
 | 
			
		||||
      originCategories: [],
 | 
			
		||||
      search: {title: null, category: ''}
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    ...mapActions(['injectJWeixin', 'wxInvoke']),
 | 
			
		||||
    handleManageType() {
 | 
			
		||||
      uni.navigateTo({url: `./typeManage?type=${this.currentType}`})
 | 
			
		||||
    },
 | 
			
		||||
    handleDetail(id) {
 | 
			
		||||
      uni.navigateTo({url: `./replyDetail?type=${this.currentType}&id=${id}`})
 | 
			
		||||
    },
 | 
			
		||||
    handleDel(id) {
 | 
			
		||||
      this.$confirm("是否要删除该话术模板").then(() => {
 | 
			
		||||
        this.$http.post("/app/wxcp/wxspeechtechnique/delete", null, {
 | 
			
		||||
          params: {id}
 | 
			
		||||
        }).then(res => {
 | 
			
		||||
          if (res?.code == 0) {
 | 
			
		||||
            this.$u.toast("删除成功!")
 | 
			
		||||
            this.getList()
 | 
			
		||||
          }
 | 
			
		||||
        })
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
    getList() {
 | 
			
		||||
      this.$http.post("/app/wxcp/wxspeechtechnique/list", null, {
 | 
			
		||||
        params: {...this.page, ...this.search, type: this.currentType}
 | 
			
		||||
      }).then(res => {
 | 
			
		||||
        if (res?.data) {
 | 
			
		||||
          if (this.page.current > 1) {
 | 
			
		||||
            this.list = [...this.list, ...res.data.records]
 | 
			
		||||
          } else this.list = res.data.records
 | 
			
		||||
          this.page.total = res.data.total
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
    getCategories() {
 | 
			
		||||
      this.$http.post("/app/wxcp/wxspeechtechniquecategory/listAll?type=-1").then(res => {
 | 
			
		||||
        if (res?.data) {
 | 
			
		||||
          this.originCategories = res.data
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
    handleTabClick(i) {
 | 
			
		||||
      this.page.current = 1
 | 
			
		||||
      this.search = {}
 | 
			
		||||
      this.currentType = i
 | 
			
		||||
      this.getList()
 | 
			
		||||
    },
 | 
			
		||||
    handleSendMsg(e) {
 | 
			
		||||
      let params = {
 | 
			
		||||
        text: {
 | 
			
		||||
          content: e.content || ""
 | 
			
		||||
        },
 | 
			
		||||
        image: {
 | 
			
		||||
          mediaid: e.mediaId || "" //图片的素材id
 | 
			
		||||
        },
 | 
			
		||||
        video: {
 | 
			
		||||
          mediaid: e.mediaId || "" //视频的素材id
 | 
			
		||||
        },
 | 
			
		||||
        file: {
 | 
			
		||||
          mediaid: e.mediaId || "" //文件的素材id
 | 
			
		||||
        },
 | 
			
		||||
        news: {
 | 
			
		||||
          link: e.accessUrl, //H5消息页面url 必填
 | 
			
		||||
          title: e.accessTitle, //H5消息标题
 | 
			
		||||
          desc: e.accessUrl,
 | 
			
		||||
          imgUrl: this.$cdn + 'file.png', //H5消息封面图片URL
 | 
			
		||||
        },
 | 
			
		||||
        miniprogram: {
 | 
			
		||||
          appid: e.accessAppid,//小程序的appid
 | 
			
		||||
          title: e.accessTitle, //小程序消息的title
 | 
			
		||||
          imgUrl: this.$cdn + 'miniwxmp.jpg',
 | 
			
		||||
          page: e.accessUrl, //小程序消息打开后的路径,注意要以.html作为后缀,否则在微信端打开会提示找不到页面
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      this.wxInvoke(['sendChatMessage', {
 | 
			
		||||
        msgtype: e.contentType,
 | 
			
		||||
        [e.contentType]: params[e.contentType]
 | 
			
		||||
      }, res => {
 | 
			
		||||
        if (res?.err_msg == 'sendChatMessage:ok') {
 | 
			
		||||
          // this.$u.toast("发送成功!")
 | 
			
		||||
        } else {
 | 
			
		||||
          this.$u.toast("发送失败!")
 | 
			
		||||
        }
 | 
			
		||||
      }])
 | 
			
		||||
    },
 | 
			
		||||
    handleTop(row) {
 | 
			
		||||
      let {isTop, id} = row
 | 
			
		||||
      isTop = (Number(isTop) + 1) % 2
 | 
			
		||||
      this.$http.post("/app/wxcp/wxspeechtechnique/setIsTop", null, {
 | 
			
		||||
        params: {isTop, id}
 | 
			
		||||
      }).then(res => {
 | 
			
		||||
        if (res?.code == 0) {
 | 
			
		||||
          this.$u.toast("设置成功!")
 | 
			
		||||
          this.getList()
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  created() {
 | 
			
		||||
    this.injectJWeixin("sendChatMessage")
 | 
			
		||||
    this.getList()
 | 
			
		||||
    this.getCategories()
 | 
			
		||||
  },
 | 
			
		||||
  onReachBottom() {
 | 
			
		||||
    if (this.page.total > this.list.length) {
 | 
			
		||||
      this.page.current++
 | 
			
		||||
      this.getList()
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
.quickReply {
 | 
			
		||||
  min-height: 100%;
 | 
			
		||||
  background: #F5F5F5;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-direction: column;
 | 
			
		||||
 | 
			
		||||
  .topFixed {
 | 
			
		||||
    background: transparent;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ::v-deep .u-tabs {
 | 
			
		||||
 | 
			
		||||
    .u-scroll-box {
 | 
			
		||||
      border-bottom: 1px solid #D4D4D4;
 | 
			
		||||
 | 
			
		||||
      .u-tab-bar {
 | 
			
		||||
        position: absolute;
 | 
			
		||||
        bottom: -6px;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ::v-deep .u-row {
 | 
			
		||||
    flex-shrink: 0;
 | 
			
		||||
    flex-wrap: nowrap;
 | 
			
		||||
    align-items: center;
 | 
			
		||||
 | 
			
		||||
    .manage {
 | 
			
		||||
      flex-shrink: 0;
 | 
			
		||||
      margin-bottom: 16px;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .top {
 | 
			
		||||
      width: 84px;
 | 
			
		||||
      height: 48px;
 | 
			
		||||
      background: #F7F7F7;
 | 
			
		||||
      border-radius: 4px;
 | 
			
		||||
      color: #999;
 | 
			
		||||
      font-size: 26px;
 | 
			
		||||
      display: flex;
 | 
			
		||||
      justify-content: center;
 | 
			
		||||
      align-items: center;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .mainPanel {
 | 
			
		||||
    padding: 40px 32px 110px;
 | 
			
		||||
    box-sizing: border-box;
 | 
			
		||||
    display: flex;
 | 
			
		||||
    flex-direction: column;
 | 
			
		||||
    justify-content: flex-start;
 | 
			
		||||
 | 
			
		||||
    & > * + * {
 | 
			
		||||
      margin-top: 32px;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .menu {
 | 
			
		||||
      text-align: center;
 | 
			
		||||
      line-height: 80px;
 | 
			
		||||
      width: 192px;
 | 
			
		||||
      height: 80px;
 | 
			
		||||
      font-size: 28px;
 | 
			
		||||
      font-weight: 400;
 | 
			
		||||
      color: #333333;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .AiCard {
 | 
			
		||||
      margin-bottom: 32px;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .addBtn {
 | 
			
		||||
    position: fixed;
 | 
			
		||||
    right: 32px;
 | 
			
		||||
    bottom: 64px;
 | 
			
		||||
    color: $uni-color-primary;
 | 
			
		||||
    font-size: 96px;
 | 
			
		||||
    text-align: center;
 | 
			
		||||
    font-weight: lighter;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .textContent {
 | 
			
		||||
    overflow: hidden;
 | 
			
		||||
    text-overflow: ellipsis;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .fileContent {
 | 
			
		||||
    display: flex;
 | 
			
		||||
    font-size: 32px;
 | 
			
		||||
    align-items: center;
 | 
			
		||||
 | 
			
		||||
    .info {
 | 
			
		||||
      display: flex;
 | 
			
		||||
      flex-direction: column;
 | 
			
		||||
      justify-content: center;
 | 
			
		||||
      flex: 1;
 | 
			
		||||
      min-width: 0;
 | 
			
		||||
 | 
			
		||||
      & > * {
 | 
			
		||||
        width: 100%;
 | 
			
		||||
        word-break: break-all;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .AiImage {
 | 
			
		||||
      margin-right: 20px;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    em {
 | 
			
		||||
      font-style: inherit;
 | 
			
		||||
      font-size: 26px;
 | 
			
		||||
      color: #9b9b9b;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										199
									
								
								src/pages/quickReply/replyDetail.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,199 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <section class="replyDetail">
 | 
			
		||||
    <u-form :model="form" ref="replyForm" :rules="rules">
 | 
			
		||||
      <u-form-item label="分类" prop="category" required>
 | 
			
		||||
        <ai-select :value="form.category" :list="categories" @data="v=>form.category=v[0].value"/>
 | 
			
		||||
      </u-form-item>
 | 
			
		||||
      <u-form-item label="标题">
 | 
			
		||||
        <u-input class="textRight" v-model="form.title" placeholder="选填,仅内部可见" maxlength="30"/>
 | 
			
		||||
      </u-form-item>
 | 
			
		||||
      <u-form-item label="快捷回复类型" label-position="top" prop="contentType" required>
 | 
			
		||||
        <ai-tabs wrap plain :ops="types" v-model="form.contentType" @change="$refs.replyForm.setRules(rules)"/>
 | 
			
		||||
      </u-form-item>
 | 
			
		||||
      <u-form-item v-if="form.contentType=='text'" label="内容" label-position="top" prop="content" required>
 | 
			
		||||
        <ai-textarea v-model="form.content" maxlength="1000" placeholder="限1000字">
 | 
			
		||||
          <template #bar>
 | 
			
		||||
            <div class="textareaBtn" @tap="handleInsert(custom.name)">插入用户昵称</div>
 | 
			
		||||
            <!--            <div class="textareaBtn" @tap="handleInsert(custom.name)">插入备注名</div>-->
 | 
			
		||||
          </template>
 | 
			
		||||
        </ai-textarea>
 | 
			
		||||
      </u-form-item>
 | 
			
		||||
      <u-form-item v-else-if="['image','video','file','voice'].includes(form.contentType)"
 | 
			
		||||
                   :label="currentContentType.name"
 | 
			
		||||
                   label-position="top" prop="mediaId" required>
 | 
			
		||||
        <ai-uploader :type="form.contentType" :mediaId.sync="form.mediaId" :fileId.sync="form.fileId"
 | 
			
		||||
                     :placeholder="`添加${currentContentType.name}`" :def="form.file"/>
 | 
			
		||||
      </u-form-item>
 | 
			
		||||
      <template v-else-if="['news'].includes(form.contentType)">
 | 
			
		||||
        <u-form-item label="链接地址" label-position="top" prop="accessUrl" required>
 | 
			
		||||
          <u-input v-model="form.accessUrl" placeholder="链接地址请以http或https开头"/>
 | 
			
		||||
        </u-form-item>
 | 
			
		||||
        <u-form-item label="标题" prop="accessTitle" required>
 | 
			
		||||
          <u-input class="textRight" v-model="form.accessTitle" maxlength="50" placeholder="请输入链接标题"/>
 | 
			
		||||
        </u-form-item>
 | 
			
		||||
      </template>
 | 
			
		||||
      <template v-else-if="['miniprogram'].includes(form.contentType)">
 | 
			
		||||
        <u-form-item label="AppId" prop="accessAppid" required>
 | 
			
		||||
          <u-input class="textRight" v-model="form.accessAppid" placeholder="请输入小程序Appid"/>
 | 
			
		||||
        </u-form-item>
 | 
			
		||||
        <u-form-item label="页面路径" prop="accessUrl" required label-width="140">
 | 
			
		||||
          <u-input class="textRight" v-model="form.accessUrl" placeholder="请输入小程序页面路径"/>
 | 
			
		||||
        </u-form-item>
 | 
			
		||||
        <u-form-item label="标题" prop="accessTitle" required>
 | 
			
		||||
          <u-input class="textRight" v-model="form.accessTitle" maxlength="50" placeholder="请输入链接标题"/>
 | 
			
		||||
        </u-form-item>
 | 
			
		||||
      </template>
 | 
			
		||||
    </u-form>
 | 
			
		||||
    <div bottom>
 | 
			
		||||
      <u-button @tap="back">取消</u-button>
 | 
			
		||||
      <u-button type="primary" @tap="submitReply">保存</u-button>
 | 
			
		||||
    </div>
 | 
			
		||||
  </section>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import AiSelect from "../../components/AiSelect";
 | 
			
		||||
import AiTabs from "../../components/AiTabs";
 | 
			
		||||
import AiTextarea from "../../components/AiTextarea";
 | 
			
		||||
import AiUploader from "../../components/AiUploader";
 | 
			
		||||
import {mapActions} from "vuex";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: "replyDetail",
 | 
			
		||||
  components: {AiUploader, AiTextarea, AiTabs, AiSelect},
 | 
			
		||||
  computed: {
 | 
			
		||||
    types() {
 | 
			
		||||
      return [
 | 
			
		||||
        {name: "文字", value: "text"},
 | 
			
		||||
        {name: "图片", value: "image"},
 | 
			
		||||
        {name: "视频", value: "video"},
 | 
			
		||||
        {name: "附件", value: "file"},
 | 
			
		||||
        {name: "链接", value: "news"},
 | 
			
		||||
        {name: "小程序", value: "miniprogram"},
 | 
			
		||||
      ]
 | 
			
		||||
    },
 | 
			
		||||
    currentContentType() {
 | 
			
		||||
      return this.types.find(e => e.value == this.form.contentType) || {}
 | 
			
		||||
    },
 | 
			
		||||
    rules() {
 | 
			
		||||
      return {
 | 
			
		||||
        category: [{required: true, message: "请选择分类"}],
 | 
			
		||||
        contentType: [{required: true, message: "请选择快捷回复类型"}],
 | 
			
		||||
        content: [{required: true, message: "请填写内容"}],
 | 
			
		||||
        accessUrl: [{required: true, message: "请填写链接地址"}],
 | 
			
		||||
        accessAppid: [{required: true, message: "请填写小程序AppId"}],
 | 
			
		||||
        accessTitle: [{required: true, message: "请填写标题"}],
 | 
			
		||||
        mediaId: [{required: true, message: `请上传${this.currentContentType.name}`}],
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  data() {
 | 
			
		||||
    return {
 | 
			
		||||
      form: {contentType: "text"},
 | 
			
		||||
      categories: [],
 | 
			
		||||
      type: "",
 | 
			
		||||
      custom: {}
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    ...mapActions(['injectJWeixin', 'wxInvoke']),
 | 
			
		||||
    back() {
 | 
			
		||||
      uni.redirectTo({url: "./quickReply"})
 | 
			
		||||
    },
 | 
			
		||||
    getCategories() {
 | 
			
		||||
      this.$http.post("/app/wxcp/wxspeechtechniquecategory/listAll", null, {
 | 
			
		||||
        params: {type: this.type}
 | 
			
		||||
      }).then(res => {
 | 
			
		||||
        if (res?.data) {
 | 
			
		||||
          this.categories = res.data.map(e => ({label: e.name, value: e.id}))
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
    getDetail(id) {
 | 
			
		||||
      this.$http.post("/app/wxcp/wxspeechtechnique/list", null, {
 | 
			
		||||
        params: {id}
 | 
			
		||||
      }).then(res => {
 | 
			
		||||
        if (res?.data) {
 | 
			
		||||
          this.form = res.data.records?.[0]
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
    submitReply() {
 | 
			
		||||
      this.$refs.replyForm.validate(v => {
 | 
			
		||||
        if (v) {
 | 
			
		||||
          this.$http.post("/app/wxcp/wxspeechtechnique/addOrUpdate", {...this.form, type: this.type}).then(res => {
 | 
			
		||||
            if (res?.code == 0) {
 | 
			
		||||
              this.$u.toast("提交成功!")
 | 
			
		||||
              uni.navigateTo({url: './quickReply'})
 | 
			
		||||
            }
 | 
			
		||||
          })
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
    getCustom() {
 | 
			
		||||
      this.wxInvoke(['getCurExternalContact', {}, res => {
 | 
			
		||||
        if (res?.err_msg == 'getCurExternalContact:ok') {
 | 
			
		||||
          this.$http.post("/app/wxcp/wxcustomer/queryCustomerById", null, {
 | 
			
		||||
            params: {id: res.userId}
 | 
			
		||||
          }).then(ret => {
 | 
			
		||||
            if (ret?.data) {
 | 
			
		||||
              this.custom = ret.data
 | 
			
		||||
            }
 | 
			
		||||
          })
 | 
			
		||||
        }
 | 
			
		||||
      }])
 | 
			
		||||
    },
 | 
			
		||||
    handleInsert(str) {
 | 
			
		||||
      if (str) {
 | 
			
		||||
        this.form.content = (this.form.content || "") + str
 | 
			
		||||
        this.$forceUpdate()
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  created() {
 | 
			
		||||
    this.injectJWeixin("getCurExternalContact").then(() => this.getCustom())
 | 
			
		||||
    let {type, id} = this.$route.query
 | 
			
		||||
    this.type = type
 | 
			
		||||
    this.getCategories()
 | 
			
		||||
    id && this.getDetail(id)
 | 
			
		||||
  },
 | 
			
		||||
  mounted() {
 | 
			
		||||
    this.$nextTick(() => this.$refs.replyForm.setRules(this.rules))
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
.replyDetail {
 | 
			
		||||
  border-top: 1px solid #D4D4D4;
 | 
			
		||||
  padding: 16px 0 208px;
 | 
			
		||||
  background: #F5F5F5;
 | 
			
		||||
  box-sizing: border-box;
 | 
			
		||||
 | 
			
		||||
  ::v-deep .u-form-item {
 | 
			
		||||
 | 
			
		||||
    .u-form-item--left {
 | 
			
		||||
      margin-bottom: 0 !important;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .u-form-item--right__content__slot {
 | 
			
		||||
      justify-content: flex-end;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    & + .u-form-item {
 | 
			
		||||
      margin-top: 16px;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .textRight {
 | 
			
		||||
      .uni-input-wrapper {
 | 
			
		||||
        text-align: right;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .textareaBtn {
 | 
			
		||||
    font-size: 26px;
 | 
			
		||||
    color: #1365DD;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										162
									
								
								src/pages/quickReply/typeManage.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,162 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <section class="typeManage">
 | 
			
		||||
    <v-drag v-model="list" @move="handleMove">
 | 
			
		||||
      <div class="item" v-for="(e,i) in list" :key="i">
 | 
			
		||||
        <u-icon name="list"/>
 | 
			
		||||
        <u-input v-model="e.name" border :focus="!e.id" @blur="submitCategory(e,i)" maxlength="6"/>
 | 
			
		||||
        <div btn @tap="handleDel(e,i)">删除</div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </v-drag>
 | 
			
		||||
    <div v-if="!adding" class="item" @tap="handleAdd">
 | 
			
		||||
      <u-icon name="plus-circle" size="38" color="#1365DD"/>
 | 
			
		||||
      <div btn>添加新的分组</div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div bottom>
 | 
			
		||||
      <u-button @tap="back">返回</u-button>
 | 
			
		||||
    </div>
 | 
			
		||||
  </section>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import VDrag from "../../components/VDrag";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: "typeManage",
 | 
			
		||||
  components: {VDrag},
 | 
			
		||||
  data() {
 | 
			
		||||
    return {
 | 
			
		||||
      list: [],
 | 
			
		||||
      adding: false,
 | 
			
		||||
      moveIndex: 0
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    back() {
 | 
			
		||||
      uni.redirectTo({url: "./quickReply"})
 | 
			
		||||
    },
 | 
			
		||||
    getList() {
 | 
			
		||||
      this.$http.post("/app/wxcp/wxspeechtechniquecategory/listAll", null, {
 | 
			
		||||
        params: {type: this.$route.query?.type}
 | 
			
		||||
      }).then(res => {
 | 
			
		||||
        if (res?.data) {
 | 
			
		||||
          this.list = res.data.map(e => ({...e, disabled: true})).sort((a, b) => a.showIndex - b.showIndex)
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
    handleAdd() {
 | 
			
		||||
      this.adding = true
 | 
			
		||||
      this.list.push({
 | 
			
		||||
        showIndex: this.list.length,
 | 
			
		||||
        type: this.$route.query?.type
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
    handleDel(item, index) {
 | 
			
		||||
      this.$confirm("是否要删除该分类?").then(() => {
 | 
			
		||||
        if (item?.id) {
 | 
			
		||||
          this.$http.post("/app/wxcp/wxspeechtechniquecategory/delete", null, {
 | 
			
		||||
            params: {id: item.id}
 | 
			
		||||
          }).then(() => {
 | 
			
		||||
            this.$u.toast("删除成功!")
 | 
			
		||||
            this.getList()
 | 
			
		||||
          })
 | 
			
		||||
        } else this.list.splice(index, 1)
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
    submitCategory(item, index) {
 | 
			
		||||
      this.adding = false
 | 
			
		||||
      if (item?.name) {
 | 
			
		||||
        this.$http.post("/app/wxcp/wxspeechtechniquecategory/addOrUpdate", item).then(() => {
 | 
			
		||||
          this.getList()
 | 
			
		||||
        })
 | 
			
		||||
      } else {
 | 
			
		||||
        this.list.splice(index, 1)
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    handleMove({moved}) {
 | 
			
		||||
      if (moved) {
 | 
			
		||||
        let {oldIndex, newIndex} = moved,
 | 
			
		||||
            list = JSON.parse(JSON.stringify(this.list)),
 | 
			
		||||
            item = list?.[oldIndex]
 | 
			
		||||
        if (oldIndex < newIndex) {
 | 
			
		||||
          list.splice(newIndex + 1, 0, item)
 | 
			
		||||
          list.splice(oldIndex, 1)
 | 
			
		||||
        } else {
 | 
			
		||||
          list.splice(oldIndex, 1)
 | 
			
		||||
          list.splice(newIndex, 0, item)
 | 
			
		||||
        }
 | 
			
		||||
        this.$http.post("/app/wxcp/wxspeechtechniquecategory/updateSort",
 | 
			
		||||
            list.map((e, showIndex) => ({id: e.id, showIndex}))
 | 
			
		||||
        ).then(res => {
 | 
			
		||||
          if (res?.code == 0) {
 | 
			
		||||
            this.getList()
 | 
			
		||||
          }
 | 
			
		||||
        })
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  created() {
 | 
			
		||||
    this.getList()
 | 
			
		||||
  },
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
.typeManage {
 | 
			
		||||
  padding: 32px 0 80px;
 | 
			
		||||
  border-top: 1px solid #D4D4D4;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-direction: column;
 | 
			
		||||
 | 
			
		||||
  & > * + * {
 | 
			
		||||
    margin-top: 32px;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  uni-movable-area {
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    height: auto;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .item {
 | 
			
		||||
    display: flex;
 | 
			
		||||
    height: 88px;
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    align-items: center;
 | 
			
		||||
    position: relative;
 | 
			
		||||
 | 
			
		||||
    & + .item {
 | 
			
		||||
      margin-top: 32px;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    &:hover {
 | 
			
		||||
      z-index: 9;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .iconfont, .u-icon {
 | 
			
		||||
    font-size: 38px;
 | 
			
		||||
    padding: 0 32px;
 | 
			
		||||
    color: #89b;
 | 
			
		||||
 | 
			
		||||
    & + div[btn] {
 | 
			
		||||
      padding: 0;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  div[btn] {
 | 
			
		||||
    color: #1365DD;
 | 
			
		||||
    padding: 0 26px;
 | 
			
		||||
    cursor: pointer;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ::v-deep .u-input {
 | 
			
		||||
    background: #FBFBFB;
 | 
			
		||||
    border-radius: 4px;
 | 
			
		||||
    border: 1px solid #CCCCCC;
 | 
			
		||||
    height: 100%;
 | 
			
		||||
 | 
			
		||||
    uni-input {
 | 
			
		||||
      height: 100%;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										100
									
								
								src/pages/resident/comp.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,100 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <section class="comp">
 | 
			
		||||
    <ai-result v-if="error" status="error" :tips="error"/>
 | 
			
		||||
    <template v-else-if="isNormal">
 | 
			
		||||
      <component ref="currentTab" :is="currentTab.comp" :isNormal="isNormal"/>
 | 
			
		||||
      <ai-tabbar :active.sync="active" :list="bottomBar"/>
 | 
			
		||||
    </template>
 | 
			
		||||
    <ai-loading v-else tips="居民管理加载中..."/>
 | 
			
		||||
  </section>
 | 
			
		||||
</template>
 | 
			
		||||
<script>
 | 
			
		||||
import {mapActions} from "vuex";
 | 
			
		||||
import AiLoading from "../../components/AiLoading";
 | 
			
		||||
import AiResult from "../../components/AiResult";
 | 
			
		||||
import ResidentSta from "./residentSta";
 | 
			
		||||
import ResidentList from "./residentList";
 | 
			
		||||
import GroupList from "./groupList";
 | 
			
		||||
import AiTabbar from "../../components/AiTabbar";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: "comp",
 | 
			
		||||
  components: {AiTabbar, GroupList, ResidentList, ResidentSta, AiResult, AiLoading},
 | 
			
		||||
  data() {
 | 
			
		||||
    return {
 | 
			
		||||
      error: "",
 | 
			
		||||
      active: 0,
 | 
			
		||||
      isNormal: false
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  computed: {
 | 
			
		||||
    bottomBar() {
 | 
			
		||||
      const link = icon => `${this.$cdn}resident/${icon}.png`
 | 
			
		||||
      return [
 | 
			
		||||
        {text: "统计分析", iconPath: "qwhome2", selectedIconPath: "qwhome1", comp: ResidentSta},
 | 
			
		||||
        {text: "居民列表", iconPath: "qwjmda1", selectedIconPath: "qwjmda2", comp: ResidentList},
 | 
			
		||||
        {text: "居民群列表", iconPath: "qwjmq1", selectedIconPath: "qwjmq2", comp: GroupList},
 | 
			
		||||
      ].map(e => ({
 | 
			
		||||
        ...e,
 | 
			
		||||
        iconPath: link(e.iconPath),
 | 
			
		||||
        selectedIconPath: link(e.selectedIconPath)
 | 
			
		||||
      }))
 | 
			
		||||
    },
 | 
			
		||||
    currentTab() {
 | 
			
		||||
      return this.bottomBar?.[this.active] || {}
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    ...mapActions(['injectJWeixin', "wxInvoke"]),
 | 
			
		||||
 | 
			
		||||
  },
 | 
			
		||||
  created() {
 | 
			
		||||
    if (this.$route.hash == "#dev") {
 | 
			
		||||
      this.isNormal = true
 | 
			
		||||
    } else this.injectJWeixin(["getContext", "getCurExternalChat"]).then(() => {
 | 
			
		||||
      this.wxInvoke(['getContext', {}, res => {
 | 
			
		||||
        if (res.err_msg == "getContext:ok") {
 | 
			
		||||
          if (res.entry == 'normal') this.isNormal = true
 | 
			
		||||
          else this.wxInvoke(['getCurExternalChat', {}, res => {
 | 
			
		||||
            if (res?.err_msg == 'getCurExternalChat:ok') {
 | 
			
		||||
              wx.redirectTo({
 | 
			
		||||
                url: "./groupResident"
 | 
			
		||||
              })
 | 
			
		||||
            } else {
 | 
			
		||||
              wx.redirectTo({
 | 
			
		||||
                url: "./resident"
 | 
			
		||||
              })
 | 
			
		||||
            }
 | 
			
		||||
          }])
 | 
			
		||||
        } else {
 | 
			
		||||
          this.error = "wxwork:获取进入场景失败"
 | 
			
		||||
        }
 | 
			
		||||
      }])
 | 
			
		||||
    }).catch(() => {
 | 
			
		||||
      this.error = "应用加载失败"
 | 
			
		||||
    })
 | 
			
		||||
  },
 | 
			
		||||
  onReachBottom() {
 | 
			
		||||
    if (typeof this.$refs?.currentTab?.reachBottom == 'function') this.$refs?.currentTab.reachBottom()
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
.comp {
 | 
			
		||||
  height: 100%;
 | 
			
		||||
 | 
			
		||||
  ::v-deep .u-tabbar__content__item {
 | 
			
		||||
    padding: 0;
 | 
			
		||||
 | 
			
		||||
    .u-icon__img {
 | 
			
		||||
      height: 44px !important;
 | 
			
		||||
      width: 44px !important;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .u-tabbar__content__item__text {
 | 
			
		||||
      margin-top: 4px;
 | 
			
		||||
      font-size: 22px;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										132
									
								
								src/pages/resident/document.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,132 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <section class="document">
 | 
			
		||||
    <div class="card">
 | 
			
		||||
      <div class="info">
 | 
			
		||||
        <u-image border-radius="4" :src="top.detail.avatar" width="118" height="118"/>
 | 
			
		||||
        <div class="fill">
 | 
			
		||||
          <b>{{ top.detail.realName || top.detail.name }}</b>
 | 
			
		||||
          <u-row>
 | 
			
		||||
            <span class="idNumber" v-html="IDObj.id"/>
 | 
			
		||||
            <a @tap="showID=!showID">{{ IDObj.btn }}</a>
 | 
			
		||||
          </u-row>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
      <ai-cell label="性别">{{ $dict.getLabel("sex", resident.sex) || "-" }}</ai-cell>
 | 
			
		||||
      <ai-cell label="出生日期">{{ resident.birthDate }}</ai-cell>
 | 
			
		||||
      <ai-cell label="年龄">{{ resident.age }}</ai-cell>
 | 
			
		||||
      <ai-cell label="籍贯">{{ resident.birthplaceAreaName }}</ai-cell>
 | 
			
		||||
      <ai-cell label="民族">{{ $dict.getLabel("nation", resident.nation) || "-" }}</ai-cell>
 | 
			
		||||
      <ai-cell label="文化程度">{{ $dict.getLabel("education", resident.education) || "-" }}</ai-cell>
 | 
			
		||||
      <ai-cell label="兵役状况">{{ $dict.getLabel("militaryStatus", resident.militaryStatus) || "-" }}</ai-cell>
 | 
			
		||||
      <ai-cell label="政治面貌">{{ $dict.getLabel("politicsStatus", resident.politicsStatus) || "-" }}</ai-cell>
 | 
			
		||||
      <ai-cell label="职业">{{ $dict.getLabel("job", resident.job) || "-" }}</ai-cell>
 | 
			
		||||
      <ai-cell label="宗教信仰">{{ $dict.getLabel("faithType", resident.faithType) || "-" }}</ai-cell>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="card">
 | 
			
		||||
      <ai-cell title label="联络信息"/>
 | 
			
		||||
      <ai-cell label="联系方式">{{ resident.phone }}</ai-cell>
 | 
			
		||||
      <ai-cell label="现住址">{{ resident.currentAreaName + resident.currentAddress }}</ai-cell>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="card">
 | 
			
		||||
      <ai-cell title label="家庭信息"/>
 | 
			
		||||
      <ai-cell label="是否户主">{{ $dict.getLabel("householdName", resident.householdName) || "-" }}</ai-cell>
 | 
			
		||||
      <ai-cell label="与户主关系">{{ $dict.getLabel("householdRelation", resident.householdRelation) || "-" }}</ai-cell>
 | 
			
		||||
      <ai-cell label="现住址">{{ resident.householdAreaName + resident.householdAddress }}</ai-cell>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="card">
 | 
			
		||||
      <ai-cell title label="家庭成员"/>
 | 
			
		||||
      <ai-table :data="family" :colConfigs="colConfigs"/>
 | 
			
		||||
    </div>
 | 
			
		||||
  </section>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import AiCell from "../../components/AiCell";
 | 
			
		||||
import AiTable from "../../components/AiTable";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: "document",
 | 
			
		||||
  components: {AiTable, AiCell},
 | 
			
		||||
  inject: ['top'],
 | 
			
		||||
  computed: {
 | 
			
		||||
    IDObj() {
 | 
			
		||||
      return this.showID ? {
 | 
			
		||||
        id: this.resident?.idNumber,
 | 
			
		||||
        btn: '隐藏'
 | 
			
		||||
      } : {
 | 
			
		||||
        id: this.resident?.idNumber?.replace(/(\d{10}).+/g, '$1******'),
 | 
			
		||||
        btn: '显示'
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    colConfigs() {
 | 
			
		||||
      return [
 | 
			
		||||
        {label: "与户主关系", prop: "householdRelation", width: '160rpx', dict: "householdRelation"},
 | 
			
		||||
        {label: "姓名", prop: "name", width: '120rpx'},
 | 
			
		||||
        {label: "性别", prop: "sex", dict: "sex"},
 | 
			
		||||
        {label: "年龄", prop: "age"},
 | 
			
		||||
        {label: "身份证号", prop: "idNumber", width: '320rpx'},
 | 
			
		||||
      ]
 | 
			
		||||
    },
 | 
			
		||||
    resident() {
 | 
			
		||||
      let obj = {}
 | 
			
		||||
      Object.keys(this.top.detail?.residentInfo?.resident || {}).map(e => {
 | 
			
		||||
        obj[e] = this.top.detail?.residentInfo?.resident[e] || ""
 | 
			
		||||
      })
 | 
			
		||||
      return obj
 | 
			
		||||
    },
 | 
			
		||||
    family() {
 | 
			
		||||
      return this.top.detail?.residentInfo?.family?.map(e => ({...e, householdRelation: e.householdRelation || "户主"}))
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  data() {
 | 
			
		||||
    return {
 | 
			
		||||
      showID: false,
 | 
			
		||||
      familyList: []
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  created() {
 | 
			
		||||
    this.$dict.load("sex", "nation", "education", "job",
 | 
			
		||||
        "faithType", "politicsStatus", "militaryStatus", "householdRelation",
 | 
			
		||||
        "householdName")
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
.document {
 | 
			
		||||
  overflow-y: auto;
 | 
			
		||||
  background: #F5F5F5;
 | 
			
		||||
 | 
			
		||||
  .info {
 | 
			
		||||
    height: 186px;
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    display: flex;
 | 
			
		||||
    align-items: center;
 | 
			
		||||
 | 
			
		||||
    .fill {
 | 
			
		||||
      color: #3C7FC8;
 | 
			
		||||
      margin-left: 24px;
 | 
			
		||||
      font-size: 28px;
 | 
			
		||||
      line-height: 40px;
 | 
			
		||||
      display: flex;
 | 
			
		||||
      flex-direction: column;
 | 
			
		||||
 | 
			
		||||
      b {
 | 
			
		||||
        font-size: 36px;
 | 
			
		||||
        color: #333;
 | 
			
		||||
        margin-bottom: 8px;
 | 
			
		||||
        line-height: 50px;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      a {
 | 
			
		||||
        cursor: pointer;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .idNumber {
 | 
			
		||||
        margin-right: 16px;
 | 
			
		||||
        color: #999;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										182
									
								
								src/pages/resident/groupList.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,182 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <section class="groupList">
 | 
			
		||||
    <ai-top-fixed>
 | 
			
		||||
      <u-search placeholder="请输入群名、群主名" :show-action="false" search-icon-color="#ccc"
 | 
			
		||||
                v-model="search.name" @search="page.current=1,getList()"/>
 | 
			
		||||
      <ai-cell>
 | 
			
		||||
        <b slot="label" class="title">共<i v-html="page.total||0"/>个居民群</b>
 | 
			
		||||
      </ai-cell>
 | 
			
		||||
    </ai-top-fixed>
 | 
			
		||||
    <div class="mainPane">
 | 
			
		||||
      <ai-cell v-for="item in list" :key="item.id" @click.native="showResident(item)">
 | 
			
		||||
        <template #label>
 | 
			
		||||
          <ai-image :src="item.avatar" preview/>
 | 
			
		||||
        </template>
 | 
			
		||||
        <div class="card column start" flex>
 | 
			
		||||
          <div flex class="groupName">
 | 
			
		||||
            <b>{{ item.name || "群聊" }}</b>
 | 
			
		||||
            <div class="personCount" v-if="item.personCount">({{ item.personCount }})</div>
 | 
			
		||||
          </div>
 | 
			
		||||
          <div class="owner" v-html="`群主:${item.ownerName}`"/>
 | 
			
		||||
          <div flex class="trends">
 | 
			
		||||
            <div flex v-html="`今日入群:<em>${item.increase||0}</em>`"/>
 | 
			
		||||
            <div flex v-html="`今日退群:<p>${item.decrease||0}</p>`"/>
 | 
			
		||||
          </div>
 | 
			
		||||
        </div>
 | 
			
		||||
      </ai-cell>
 | 
			
		||||
    </div>
 | 
			
		||||
  </section>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import AiCell from "../../components/AiCell";
 | 
			
		||||
import AiImage from "../../components/AiImage";
 | 
			
		||||
import AiTopFixed from "../../components/AiTopFixed";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: "groupList",
 | 
			
		||||
  components: {AiTopFixed, AiImage, AiCell},
 | 
			
		||||
  data() {
 | 
			
		||||
    return {
 | 
			
		||||
      page: {current: 1, size: 10, total: 0},
 | 
			
		||||
      search: {name: ""},
 | 
			
		||||
      list: []
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    getList() {
 | 
			
		||||
      this.$http.post("/app/wxcp/wxgroup/list", null, {
 | 
			
		||||
        params: {...this.page, ...this.search}
 | 
			
		||||
      }).then(res => {
 | 
			
		||||
        if (res?.data) {
 | 
			
		||||
          let meta = res.data.records?.map(e => ({
 | 
			
		||||
            ...e,
 | 
			
		||||
            avatar: e?.avatar || this.$cdn + "groupAvatar.png"
 | 
			
		||||
          }))
 | 
			
		||||
          if (this.page.current > 1) {
 | 
			
		||||
            this.list = [...this.list, ...meta]
 | 
			
		||||
          } else this.list = meta
 | 
			
		||||
          this.page.total = res.data.total
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
    reachBottom() {
 | 
			
		||||
      if (this.page.total > this.list.length) {
 | 
			
		||||
        this.page.current++
 | 
			
		||||
        this.getList()
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    showResident({id}) {
 | 
			
		||||
      id && uni.navigateTo({
 | 
			
		||||
        url: './groupResident?id=' + id
 | 
			
		||||
      })
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  created() {
 | 
			
		||||
    this.getList()
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
.groupList {
 | 
			
		||||
  ::v-deep .AiTopFixed {
 | 
			
		||||
    b.title {
 | 
			
		||||
      color: #333;
 | 
			
		||||
      font-size: 32px;
 | 
			
		||||
 | 
			
		||||
      & > i {
 | 
			
		||||
        color: #267FCE;
 | 
			
		||||
        font-style: normal;
 | 
			
		||||
        margin: 0 4px;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ::v-deep .mainPane {
 | 
			
		||||
    background: #fff;
 | 
			
		||||
    padding: 0 32px;
 | 
			
		||||
 | 
			
		||||
    .AiCell {
 | 
			
		||||
      align-items: center;
 | 
			
		||||
      height: 230px;
 | 
			
		||||
      justify-content: flex-start;
 | 
			
		||||
 | 
			
		||||
      .content {
 | 
			
		||||
        flex: 1;
 | 
			
		||||
        min-width: 0;
 | 
			
		||||
        height: 100%;
 | 
			
		||||
        max-width: unset;
 | 
			
		||||
        border-bottom: 1px solid rgba(221, 221, 221, 1);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .card {
 | 
			
		||||
      height: 100%;
 | 
			
		||||
      justify-content: center;
 | 
			
		||||
 | 
			
		||||
      b {
 | 
			
		||||
        font-size: 36px;
 | 
			
		||||
        white-space: nowrap;
 | 
			
		||||
        overflow: hidden;
 | 
			
		||||
        text-overflow: ellipsis;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .tag {
 | 
			
		||||
        justify-content: center;
 | 
			
		||||
        background: #F3F4F7;
 | 
			
		||||
        border-radius: 4px;
 | 
			
		||||
        padding: 0 16px;
 | 
			
		||||
        font-size: 28px;
 | 
			
		||||
        font-weight: 400;
 | 
			
		||||
        color: #333;
 | 
			
		||||
        margin-left: 16px;
 | 
			
		||||
        height: 56px;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .groupName {
 | 
			
		||||
        width: 100%;
 | 
			
		||||
        text-align: left;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .owner, .trends {
 | 
			
		||||
        margin-top: 8px;
 | 
			
		||||
        font-size: 28px;
 | 
			
		||||
        font-weight: 400;
 | 
			
		||||
        color: #999;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .personCount {
 | 
			
		||||
        flex-shrink: 0;
 | 
			
		||||
        font-size: 30px;
 | 
			
		||||
        font-weight: 400;
 | 
			
		||||
        color: #666;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .trends {
 | 
			
		||||
        * + * {
 | 
			
		||||
          margin-left: 24px;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        em {
 | 
			
		||||
          font-style: normal;
 | 
			
		||||
          color: #5FBA95;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        p {
 | 
			
		||||
          color: #F09535;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .AiImage {
 | 
			
		||||
      margin-right: 24px;
 | 
			
		||||
 | 
			
		||||
      image {
 | 
			
		||||
        width: 112px;
 | 
			
		||||
        height: 112px;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										305
									
								
								src/pages/resident/groupResident.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,305 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="group-resident">
 | 
			
		||||
    <template v-if="!showTagManage">
 | 
			
		||||
      <ai-top-fixed>
 | 
			
		||||
        <div class="card">
 | 
			
		||||
          <header>
 | 
			
		||||
            <u-avatar mode="square" :src="$cdn + 'groupAvatar.png'" :size="112"></u-avatar>
 | 
			
		||||
            {{ detail.name }}
 | 
			
		||||
          </header>
 | 
			
		||||
          <u-grid :col="2" :border="false">
 | 
			
		||||
            <u-grid-item>
 | 
			
		||||
              <label>建群日期</label>
 | 
			
		||||
              <label v-if="detail.createTime">{{ detail.createTime.split(" ")[0] }}</label>
 | 
			
		||||
            </u-grid-item>
 | 
			
		||||
            <u-grid-item>
 | 
			
		||||
              <label>成员总数</label>
 | 
			
		||||
              <label v-if="isToday">{{ detail.statistic.today.total }}</label>
 | 
			
		||||
            </u-grid-item>
 | 
			
		||||
            <u-grid-item>
 | 
			
		||||
              <label>今日入群</label>
 | 
			
		||||
              <label v-if="isToday">{{ detail.statistic.today.increase }}</label>
 | 
			
		||||
            </u-grid-item>
 | 
			
		||||
            <u-grid-item>
 | 
			
		||||
              <label>今日退群</label>
 | 
			
		||||
              <label v-if="isToday">{{ detail.statistic.today.decrease }}</label>
 | 
			
		||||
            </u-grid-item>
 | 
			
		||||
            <!--          <u-grid-item>-->
 | 
			
		||||
            <!--            <label>今日活跃人数</label>-->
 | 
			
		||||
            <!--            <label>{{item.value}}</label>-->
 | 
			
		||||
            <!--          </u-grid-item>-->
 | 
			
		||||
          </u-grid>
 | 
			
		||||
          <p class="statistics">
 | 
			
		||||
            <span>成员性别:</span>
 | 
			
		||||
            <label>男性</label>
 | 
			
		||||
            <b>{{ detail.man }}</b>
 | 
			
		||||
            <label>女性</label>
 | 
			
		||||
            <b>{{ detail.woman }}</b>
 | 
			
		||||
            <label>未知</label>
 | 
			
		||||
            <b>{{ detail.unknown }}</b>
 | 
			
		||||
          </p>
 | 
			
		||||
        </div>
 | 
			
		||||
      </ai-top-fixed>
 | 
			
		||||
      <div class="card">
 | 
			
		||||
        <ai-cell title label="群标签">
 | 
			
		||||
          <u-icon label="添加" size="38" name="iconAdd" custom-prefix="iconfont" color="#1365DD"
 | 
			
		||||
                  label-color="#1365DD" @tap="showTagManage=true"/>
 | 
			
		||||
        </ai-cell>
 | 
			
		||||
        <ai-cell top-label v-for="(op,name) in tagsList" :label="name" :key="name">
 | 
			
		||||
          <u-row>
 | 
			
		||||
            <div class="tag" v-for="(tag,j) in op" :key="j">{{ tag }}</div>
 | 
			
		||||
          </u-row>
 | 
			
		||||
        </ai-cell>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="card">
 | 
			
		||||
        <ai-cell title label="群成员"></ai-cell>
 | 
			
		||||
        <div class="wrap">
 | 
			
		||||
          <div class="item" v-for="(item,index) in detail.groupUserList" :key="index" @click="handleWechat(item)">
 | 
			
		||||
            <u-avatar mode="square" :src="item.avatar"></u-avatar>
 | 
			
		||||
            <div class="info">
 | 
			
		||||
              <div class="left">
 | 
			
		||||
                <p>{{ item.memberName }}
 | 
			
		||||
                  <b v-if="item.customerType==2" style="color: #3C7FC8;">@{{ item.corpName }}</b>
 | 
			
		||||
                  <b v-if="item.customerType==1" style="color: #2EA222;">@微信</b>
 | 
			
		||||
                </p>
 | 
			
		||||
                <p>真实姓名:{{ item.realName }}</p>
 | 
			
		||||
              </div>
 | 
			
		||||
              <span v-if="item.userId==detail.owner">群主</span>
 | 
			
		||||
            </div>
 | 
			
		||||
          </div>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </template>
 | 
			
		||||
    <tag-manage v-if="showTagManage"/>
 | 
			
		||||
    <ai-back v-if="isNormal&&!showTagManage"/>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import AiCell from "../../components/AiCell";
 | 
			
		||||
import {mapActions} from "vuex";
 | 
			
		||||
import TagManage from "./tagManage";
 | 
			
		||||
import AiBack from "../../components/AiBack";
 | 
			
		||||
import AiTopFixed from "../../components/AiTopFixed";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: "groupResident",
 | 
			
		||||
  components: {AiTopFixed, AiBack, AiCell, TagManage},
 | 
			
		||||
  provide() {
 | 
			
		||||
    return {
 | 
			
		||||
      top: this
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  data() {
 | 
			
		||||
    return {
 | 
			
		||||
      detail: {},
 | 
			
		||||
      groupId: null,
 | 
			
		||||
      showTagManage: false,
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  computed: {
 | 
			
		||||
    tagsList() {
 | 
			
		||||
      let obj = {}
 | 
			
		||||
      this.detail?.tagList?.map(e => {
 | 
			
		||||
        if (e?.groupName) {
 | 
			
		||||
          if (obj?.[e.groupName]) {
 | 
			
		||||
            obj[e.groupName].push(e.tagName)
 | 
			
		||||
          } else {
 | 
			
		||||
            obj[e.groupName] = [e.tagName]
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
      return obj
 | 
			
		||||
    },
 | 
			
		||||
    isToday() {
 | 
			
		||||
      return !!this.detail?.statistic?.today
 | 
			
		||||
    },
 | 
			
		||||
    isNormal() {
 | 
			
		||||
      return !!this.$route.query.id;
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    ...mapActions(['injectJWeixin', "wxInvoke"]),
 | 
			
		||||
    getContact() {
 | 
			
		||||
      if (this.isNormal) {
 | 
			
		||||
        this.groupId = this.$route.query.id
 | 
			
		||||
        this.getGroup(this.$route.query.id)
 | 
			
		||||
      } else this.injectJWeixin("getCurExternalChat").then(() => {
 | 
			
		||||
        this.wxInvoke(['getCurExternalChat', {}, res => {
 | 
			
		||||
          if (res?.err_msg == 'getCurExternalChat:ok') {
 | 
			
		||||
            this.groupId = res.chatId
 | 
			
		||||
            this.getGroup(res.chatId)
 | 
			
		||||
          }
 | 
			
		||||
        }])
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
    getGroup(id) {
 | 
			
		||||
      this.$http.post("/app/wxcp/wxgroup/getDetail", null, {
 | 
			
		||||
        params: {id}
 | 
			
		||||
      }).then(res => {
 | 
			
		||||
        if (res?.data) {
 | 
			
		||||
          this.detail = res.data
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
    handleWechat({userId,type}) {
 | 
			
		||||
      this.injectJWeixin('openUserProfile').then(()=>{
 | 
			
		||||
        this.wxInvoke(['openUserProfile', {
 | 
			
		||||
          type,
 | 
			
		||||
          userid: userId
 | 
			
		||||
        }, () => 0])
 | 
			
		||||
      })
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  created() {
 | 
			
		||||
    this.getContact()
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
.group-resident {
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  min-height: 100%;
 | 
			
		||||
  background-color: #F5F5F5;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-direction: column;
 | 
			
		||||
 | 
			
		||||
  ::v-deep .AiTopFixed {
 | 
			
		||||
    & > .card {
 | 
			
		||||
      margin-top: 0;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ::v-deep .card {
 | 
			
		||||
    background-color: #FFFFFF;
 | 
			
		||||
    padding: 16px 32px;
 | 
			
		||||
    box-sizing: border-box;
 | 
			
		||||
    margin-top: 16px;
 | 
			
		||||
 | 
			
		||||
    header {
 | 
			
		||||
      height: 192px;
 | 
			
		||||
      display: flex;
 | 
			
		||||
      align-items: center;
 | 
			
		||||
      font-size: 36px;
 | 
			
		||||
      font-weight: 600;
 | 
			
		||||
      color: #333333;
 | 
			
		||||
 | 
			
		||||
      .u-avatar {
 | 
			
		||||
        margin-right: 24px;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ::v-deep .u-grid-item-box {
 | 
			
		||||
      box-sizing: border-box;
 | 
			
		||||
      padding: 16px !important;
 | 
			
		||||
 | 
			
		||||
      .uni-label-pointer {
 | 
			
		||||
        width: 100%;
 | 
			
		||||
        line-height: 40px;
 | 
			
		||||
        color: #999999;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      uni-label:last-child {
 | 
			
		||||
        margin-top: 16px;
 | 
			
		||||
        font-weight: 600;
 | 
			
		||||
        color: #333333;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .statistics {
 | 
			
		||||
      height: 96px;
 | 
			
		||||
      display: flex;
 | 
			
		||||
      align-items: center;
 | 
			
		||||
      border-top: 1px solid #eee;
 | 
			
		||||
      margin-top: 16px;
 | 
			
		||||
 | 
			
		||||
      span {
 | 
			
		||||
        font-size: 28px;
 | 
			
		||||
        color: #999999
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      label + b {
 | 
			
		||||
        font-size: 28px;
 | 
			
		||||
        color: #333333;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      b {
 | 
			
		||||
        color: #1365DD !important;
 | 
			
		||||
        margin: 0 32px 0 16px;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    & > section:first-child {
 | 
			
		||||
      height: 90px !important;
 | 
			
		||||
      display: flex;
 | 
			
		||||
      align-items: center;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .wrap {
 | 
			
		||||
      margin-bottom: 20px;
 | 
			
		||||
 | 
			
		||||
      .item {
 | 
			
		||||
        height: 176px;
 | 
			
		||||
        display: flex;
 | 
			
		||||
        align-items: center;
 | 
			
		||||
 | 
			
		||||
        .info {
 | 
			
		||||
          width: 100%;
 | 
			
		||||
          height: 100%;
 | 
			
		||||
          display: flex;
 | 
			
		||||
          align-items: center;
 | 
			
		||||
          justify-content: space-between;
 | 
			
		||||
          margin-left: 24px;
 | 
			
		||||
          border-bottom: 1px solid #eee;
 | 
			
		||||
 | 
			
		||||
          .left {
 | 
			
		||||
            font-size: 36px;
 | 
			
		||||
            font-weight: 600;
 | 
			
		||||
            color: #333333;
 | 
			
		||||
 | 
			
		||||
            b {
 | 
			
		||||
              font-size: 28px;
 | 
			
		||||
              font-weight: 400;
 | 
			
		||||
              color: #3C7FC8;
 | 
			
		||||
              margin-left: 16px;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            p:last-child {
 | 
			
		||||
              font-size: 28px;
 | 
			
		||||
              font-weight: 400;
 | 
			
		||||
              color: #999999;
 | 
			
		||||
              margin-top: 8px;
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          span {
 | 
			
		||||
            width: 88px;
 | 
			
		||||
            height: 56px;
 | 
			
		||||
            text-align: center;
 | 
			
		||||
            background: rgba(19, 101, 221, 0.1);
 | 
			
		||||
            box-shadow: 0 8px 16px 0 rgba(0, 0, 0, 0.02);
 | 
			
		||||
            border-radius: 4px;
 | 
			
		||||
            font-size: 28px;
 | 
			
		||||
            font-weight: 400;
 | 
			
		||||
            color: #1365DD;
 | 
			
		||||
            line-height: 56px;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ::v-deep .tag {
 | 
			
		||||
    height: 56px;
 | 
			
		||||
    line-height: 56px;
 | 
			
		||||
    background: #F3F4F7;
 | 
			
		||||
    border-radius: 6px;
 | 
			
		||||
    padding: 8px 16px;
 | 
			
		||||
    margin-right: 16px;
 | 
			
		||||
    margin-bottom: 16px;
 | 
			
		||||
    overflow: hidden;
 | 
			
		||||
    cursor: default;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										359
									
								
								src/pages/resident/info.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,359 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <section class="info">
 | 
			
		||||
    <div class="card">
 | 
			
		||||
      <div class="baseInfo">
 | 
			
		||||
        <u-image border-radius="4" :src="top.detail.avatar" width="118" height="118"/>
 | 
			
		||||
        <div class="fill">
 | 
			
		||||
          <b>{{ top.detail.name }}</b>
 | 
			
		||||
          <div v-if="top.detail.type==1" class="wx">@微信</div>
 | 
			
		||||
          <div v-if="top.detail.type==2">@企业微信</div>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="certBtn" @tap="handleCert">{{ !isCert ? "实名认证" : "解绑" }}</div>
 | 
			
		||||
      </div>
 | 
			
		||||
      <u-row>
 | 
			
		||||
        <ai-cell class="half" top-label label="来源">{{ $dict.getLabel("wxCustomerAddWay", top.detail.addWay) }}</ai-cell>
 | 
			
		||||
        <ai-cell class="half" top-label label="添加时间">{{ top.detail.createTime }}</ai-cell>
 | 
			
		||||
        <ai-cell class="half" top-label label="真实姓名">{{ top.detail.realName }}</ai-cell>
 | 
			
		||||
        <ai-cell class="half" top-label label="手机号码">{{ resident.phone || "-" }}</ai-cell>
 | 
			
		||||
        <ai-cell class="half" top-label label="家庭积分">{{ resident.familyIntegral }}</ai-cell>
 | 
			
		||||
        <ai-cell class="half" top-label label="个人积分">{{ resident.personalIntegral }}</ai-cell>
 | 
			
		||||
      </u-row>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="card">
 | 
			
		||||
      <ai-cell title label="公共标签">
 | 
			
		||||
        <u-icon label="添加" size="38" name="iconAdd" custom-prefix="iconfont" color="#1365DD"
 | 
			
		||||
                label-color="#1365DD" @tap="top.showTagManage=true"/>
 | 
			
		||||
      </ai-cell>
 | 
			
		||||
      <ai-cell top-label v-for="(op,name) in tagsList" :label="name" :key="name">
 | 
			
		||||
        <u-row>
 | 
			
		||||
          <div class="tag" v-for="(tag,j) in op" :key="j">{{ tag }}</div>
 | 
			
		||||
        </u-row>
 | 
			
		||||
      </ai-cell>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="card">
 | 
			
		||||
      <ai-cell title label="动态"/>
 | 
			
		||||
      <ai-cell top-label>
 | 
			
		||||
        <div class="logItem" v-for="item in customLogs" :key="item.id">
 | 
			
		||||
          <div flex class="column" shrink>
 | 
			
		||||
            <div class="dot"/>
 | 
			
		||||
            <div class="line fill"/>
 | 
			
		||||
          </div>
 | 
			
		||||
          <div flex class="start column">
 | 
			
		||||
            <b>{{ $dict.getLabel('wxCustomerLogType', item.type) }}</b>
 | 
			
		||||
            <span>{{ item.createTime }}</span>
 | 
			
		||||
            <div v-html="item.content"/>
 | 
			
		||||
          </div>
 | 
			
		||||
        </div>
 | 
			
		||||
      </ai-cell>
 | 
			
		||||
    </div>
 | 
			
		||||
    <u-mask :show="dialog" @tap="dialog=false">
 | 
			
		||||
      <div class="bindCert" @tap.stop>
 | 
			
		||||
        <b class="title">实名认证</b>
 | 
			
		||||
        <u-input class="searchInput" v-model="search" clearable placeholder="请输入姓名或身份证号" @input="handleSearch"/>
 | 
			
		||||
        <div class="residents">
 | 
			
		||||
          <div flex class="spb" v-for="(op,i) in result" :key="i" @tap="bindCert(op.id)">
 | 
			
		||||
            <div v-html="op.name"/>
 | 
			
		||||
            <div v-html="op.idNumber"/>
 | 
			
		||||
          </div>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </u-mask>
 | 
			
		||||
    <div bottom>
 | 
			
		||||
      <u-button type="primary" @tap="handleWechat">微信联系</u-button>
 | 
			
		||||
      <u-button v-if="isMobile" :disabled="!resident.phone" @tap="handleTel">电话联系</u-button>
 | 
			
		||||
    </div>
 | 
			
		||||
  </section>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import AiCell from "../../components/AiCell";
 | 
			
		||||
import UMask from "../../uview/components/u-mask/u-mask";
 | 
			
		||||
import UInput from "../../uview/components/u-input/u-input";
 | 
			
		||||
import USteps from "../../uview/components/u-steps/u-steps";
 | 
			
		||||
import ULine from "../../uview/components/u-line/u-line";
 | 
			
		||||
import UButton from "../../uview/components/u-button/u-button";
 | 
			
		||||
import {mapActions} from "vuex";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: "info",
 | 
			
		||||
  components: {UButton, ULine, USteps, UInput, UMask, AiCell},
 | 
			
		||||
  inject: ['top'],
 | 
			
		||||
  computed: {
 | 
			
		||||
    resident() {
 | 
			
		||||
      return this.top.detail?.residentInfo?.resident || {}
 | 
			
		||||
    },
 | 
			
		||||
    tagsList() {
 | 
			
		||||
      let obj = {}
 | 
			
		||||
      this.top.detail?.tags?.map(e => {
 | 
			
		||||
        if (e.type == 1 && e?.groupName) {
 | 
			
		||||
          if (obj?.[e.groupName]) {
 | 
			
		||||
            obj[e.groupName].push(e.tagName)
 | 
			
		||||
          } else {
 | 
			
		||||
            obj[e.groupName] = [e.tagName]
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
      return obj
 | 
			
		||||
    },
 | 
			
		||||
    isCert() {
 | 
			
		||||
      return !!this.top?.detail?.residentInfo
 | 
			
		||||
    },
 | 
			
		||||
    isMobile() {
 | 
			
		||||
      return ["Android", "iPhone", "SymbianOS", "Windows Phone", "iPad", "iPod"]
 | 
			
		||||
      .some(e => navigator.userAgent.indexOf(e) > -1)
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  data() {
 | 
			
		||||
    return {
 | 
			
		||||
      dialog: false,
 | 
			
		||||
      search: "",
 | 
			
		||||
      result: [],
 | 
			
		||||
      customLogs: []
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    ...mapActions(['injectJWeixin', 'wxInvoke']),
 | 
			
		||||
    searchResident() {
 | 
			
		||||
      this.$http.post("/app/appresident/check-name", null, {
 | 
			
		||||
        params: {name: this.search}
 | 
			
		||||
      }).then(res => {
 | 
			
		||||
        if (res?.data) {
 | 
			
		||||
          let reg = new RegExp(this.search, 'g')
 | 
			
		||||
          this.result = res.data?.map(e => ({
 | 
			
		||||
            ...e,
 | 
			
		||||
            name: e.name.replace(reg, `<b>${this.search}</b>`),
 | 
			
		||||
            idNumber: e.idNumber.replace(reg, `<b>${this.search}</b>`),
 | 
			
		||||
          }))
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
    handleSearch() {
 | 
			
		||||
      if (this.search?.length >= 2) {
 | 
			
		||||
        this.searchResident()
 | 
			
		||||
      } else {
 | 
			
		||||
        this.result = []
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    handleCert() {
 | 
			
		||||
      if (this.isCert) {
 | 
			
		||||
        this.$confirm("是否要解绑当前实名认证?").then(() => {
 | 
			
		||||
          this.$http.post("/app/wxcp/wxcustomer/unBindCustomer2Resident", null, {
 | 
			
		||||
            params: {residentId: this.resident.id, customerId: this.top.custom}
 | 
			
		||||
          }).then(res => {
 | 
			
		||||
            if (res?.code == 0) {
 | 
			
		||||
              this.$u.toast("解除绑定成功!")
 | 
			
		||||
              this.top.getContact()
 | 
			
		||||
            }
 | 
			
		||||
          })
 | 
			
		||||
        })
 | 
			
		||||
      } else this.dialog = true
 | 
			
		||||
    },
 | 
			
		||||
    bindCert(residentId) {
 | 
			
		||||
      this.dialog = false
 | 
			
		||||
      this.$confirm("是否要绑定该居民?").then(() => {
 | 
			
		||||
        this.$http.post("/app/wxcp/wxcustomer/bindCustomer2Resident", null, {
 | 
			
		||||
          params: {residentId, customerId: this.top.custom}
 | 
			
		||||
        }).then(res => {
 | 
			
		||||
          if (res?.code == 0) {
 | 
			
		||||
            this.$u.toast("绑定成功!")
 | 
			
		||||
            this.top.getContact()
 | 
			
		||||
          }
 | 
			
		||||
        }).catch(err => {
 | 
			
		||||
          this.$u.toast(err)
 | 
			
		||||
          setTimeout(() => this.dialog = true, 1000)
 | 
			
		||||
        })
 | 
			
		||||
      }).catch(() => this.dialog = true)
 | 
			
		||||
    },
 | 
			
		||||
    getCustomLog(customerId) {
 | 
			
		||||
      customerId && this.$http.post("/app/wxcp/wxcustomerlog/listAll", null, {
 | 
			
		||||
        params: {customerId}
 | 
			
		||||
      }).then(res => {
 | 
			
		||||
        if (res?.data) {
 | 
			
		||||
          this.customLogs = res.data
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
    handleTel() {
 | 
			
		||||
      location.href = "tel:" + this.resident.phone
 | 
			
		||||
    },
 | 
			
		||||
    handleWechat() {
 | 
			
		||||
      this.wxInvoke(['openUserProfile', {
 | 
			
		||||
        type: 2,
 | 
			
		||||
        userid: this.top.custom
 | 
			
		||||
      }, () => 0])
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  created() {
 | 
			
		||||
    this.$dict.load("wxCustomerAddWay", 'wxCustomerLogType')
 | 
			
		||||
    this.getCustomLog(this.top.custom)
 | 
			
		||||
    this.injectJWeixin('openUserProfile')
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
.info {
 | 
			
		||||
  padding-bottom: 130px;
 | 
			
		||||
  .certBtn {
 | 
			
		||||
    cursor: pointer;
 | 
			
		||||
    background: $uni-color-primary;
 | 
			
		||||
    color: #fff;
 | 
			
		||||
    padding: 8px 16px;
 | 
			
		||||
    border-radius: 4px;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .baseInfo {
 | 
			
		||||
    height: 186px;
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    display: flex;
 | 
			
		||||
    align-items: center;
 | 
			
		||||
 | 
			
		||||
    .fill {
 | 
			
		||||
      color: #3C7FC8;
 | 
			
		||||
      margin-left: 24px;
 | 
			
		||||
      font-size: 28px;
 | 
			
		||||
      line-height: 40px;
 | 
			
		||||
 | 
			
		||||
      b {
 | 
			
		||||
        font-size: 36px;
 | 
			
		||||
        color: #333;
 | 
			
		||||
        margin-bottom: 8px;
 | 
			
		||||
        line-height: 50px;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .wx {
 | 
			
		||||
        color: #2EA222;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ::v-deep .AiCell {
 | 
			
		||||
    &.half {
 | 
			
		||||
      width: 50%;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ::v-deep .u-form-item {
 | 
			
		||||
    width: 50%;
 | 
			
		||||
    min-height: 124px;
 | 
			
		||||
 | 
			
		||||
    .u-form-item--left {
 | 
			
		||||
      color: #999;
 | 
			
		||||
      min-height: 40px;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .u-form-item--right {
 | 
			
		||||
      min-height: 0;
 | 
			
		||||
      margin-top: 16px;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ::v-deep .u-mask {
 | 
			
		||||
    display: flex;
 | 
			
		||||
    align-items: center;
 | 
			
		||||
    justify-content: center;
 | 
			
		||||
 | 
			
		||||
    .bindCert {
 | 
			
		||||
      width: 600px;
 | 
			
		||||
      padding: 32px;
 | 
			
		||||
      min-height: 400px;
 | 
			
		||||
      background-color: #fff;
 | 
			
		||||
      display: flex;
 | 
			
		||||
      flex-direction: column;
 | 
			
		||||
      color: #333;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .residents {
 | 
			
		||||
      max-height: 780px;
 | 
			
		||||
      overflow-y: auto;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .title {
 | 
			
		||||
      text-align: center;
 | 
			
		||||
      font-size: 36px;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .searchInput {
 | 
			
		||||
      margin: 16px 0;
 | 
			
		||||
      border: 1px solid #D0D4DC;
 | 
			
		||||
      border-radius: 8px;
 | 
			
		||||
      padding: 0 16px !important;
 | 
			
		||||
      flex: 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .spb {
 | 
			
		||||
      height: 60px;
 | 
			
		||||
      cursor: pointer;
 | 
			
		||||
      padding: 0 16px;
 | 
			
		||||
 | 
			
		||||
      b {
 | 
			
		||||
        font-size: 32px;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      &:nth-of-type(2n) {
 | 
			
		||||
        background: #eee;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ::v-deep .logItem {
 | 
			
		||||
    display: flex;
 | 
			
		||||
    min-height: 220px;
 | 
			
		||||
 | 
			
		||||
    &:last-of-type {
 | 
			
		||||
      .line {
 | 
			
		||||
        display: none;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    & > .column + .column {
 | 
			
		||||
      margin-left: 16px;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .dot {
 | 
			
		||||
      flex-shrink: 0;
 | 
			
		||||
      width: 16px;
 | 
			
		||||
      height: 16px;
 | 
			
		||||
      background: $uni-color-primary;
 | 
			
		||||
      border: 8px solid #FFFFFF;
 | 
			
		||||
      border-radius: 50%;
 | 
			
		||||
      margin: 8px 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .line {
 | 
			
		||||
      width: 4px;
 | 
			
		||||
      background: #eee;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .start {
 | 
			
		||||
      font-size: 26px;
 | 
			
		||||
      font-weight: 400;
 | 
			
		||||
      color: #666;
 | 
			
		||||
 | 
			
		||||
      b {
 | 
			
		||||
        color: #333;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      i {
 | 
			
		||||
        color: $uni-color-primary;
 | 
			
		||||
        font-style: normal;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      & > b {
 | 
			
		||||
        font-size: 32px;
 | 
			
		||||
        font-weight: bold;
 | 
			
		||||
        margin-bottom: 8px;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      & > span {
 | 
			
		||||
        color: #999;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      & > div {
 | 
			
		||||
        margin-top: 16px;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										149
									
								
								src/pages/resident/resident.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,149 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <section class="resident">
 | 
			
		||||
    <ai-loading v-if="!custom&&!error" tips="获取居民信息中..."/>
 | 
			
		||||
    <ai-result v-else-if="error" status="error" :tips="error"/>
 | 
			
		||||
    <template v-else>
 | 
			
		||||
      <tag-manage v-if="showTagManage"/>
 | 
			
		||||
      <template v-else>
 | 
			
		||||
        <ai-top-fixed>
 | 
			
		||||
          <u-tabs :list="tabs" :is-scroll="false" :current="currentType" font-size="32"
 | 
			
		||||
                  bar-width="192" height="96" @change="handleTabClick"/>
 | 
			
		||||
        </ai-top-fixed>
 | 
			
		||||
        <component :is="currentTab.comp"/>
 | 
			
		||||
      </template>
 | 
			
		||||
    </template>
 | 
			
		||||
    <ai-back v-if="isNormal&&!showTagManage"/>
 | 
			
		||||
  </section>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import {mapActions} from "vuex";
 | 
			
		||||
import Info from "./info";
 | 
			
		||||
import Document from "./document";
 | 
			
		||||
import TagManage from "./tagManage";
 | 
			
		||||
import AiLoading from "../../components/AiLoading";
 | 
			
		||||
import AiResult from "../../components/AiResult";
 | 
			
		||||
import AiBack from "../../components/AiBack";
 | 
			
		||||
import AiTopFixed from "../../components/AiTopFixed";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: "resident",
 | 
			
		||||
  components: {AiTopFixed, AiBack, AiResult, AiLoading, TagManage, Document, Info},
 | 
			
		||||
  provide() {
 | 
			
		||||
    return {
 | 
			
		||||
      top: this
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  computed: {
 | 
			
		||||
    tabs() {
 | 
			
		||||
      return [
 | 
			
		||||
        {name: "居民信息", value: 0, comp: Info},
 | 
			
		||||
        {name: "居民档案", value: 1, comp: Document, hide: !this.detail.residentInfo},
 | 
			
		||||
      ].filter(e => !e.hide)
 | 
			
		||||
    },
 | 
			
		||||
    currentTab() {
 | 
			
		||||
      return this.tabs.find(e => e.value == this.currentType)
 | 
			
		||||
    },
 | 
			
		||||
    isNormal() {
 | 
			
		||||
      return !!this.$route.query.id;
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  data() {
 | 
			
		||||
    return {
 | 
			
		||||
      currentType: 0,
 | 
			
		||||
      detail: {},
 | 
			
		||||
      showTagManage: false,
 | 
			
		||||
      custom: "",
 | 
			
		||||
      error: ""
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    ...mapActions(['injectJWeixin', 'wxInvoke']),
 | 
			
		||||
    handleTabClick(i) {
 | 
			
		||||
      this.currentType = i
 | 
			
		||||
    },
 | 
			
		||||
    getContact() {
 | 
			
		||||
      if (this.isNormal) {
 | 
			
		||||
        this.getCustom(this.$route.query.id)
 | 
			
		||||
      } else {
 | 
			
		||||
        this.injectJWeixin("getCurExternalContact").then(() => {
 | 
			
		||||
          this.wxInvoke(['getCurExternalContact', {}, res => {
 | 
			
		||||
            if (res?.err_msg == 'getCurExternalContact:ok') {
 | 
			
		||||
              this.getCustom(res.userId)
 | 
			
		||||
            }
 | 
			
		||||
          }])
 | 
			
		||||
        }).catch(({errMsg}) => {
 | 
			
		||||
          this.error = errMsg
 | 
			
		||||
        })
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    getCustom(id) {
 | 
			
		||||
      this.$http.post("/app/wxcp/wxcustomer/queryCustomerById", null, {
 | 
			
		||||
        params: {id}
 | 
			
		||||
      }).then(ret => {
 | 
			
		||||
        if (ret?.data) {
 | 
			
		||||
          this.custom = id
 | 
			
		||||
          this.detail = ret.data
 | 
			
		||||
          if (this.detail.type == 2) {
 | 
			
		||||
            this.error = "只能查看个人微信绑定的居民信息"
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  created() {
 | 
			
		||||
    this.getContact()
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
.resident {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-direction: column;
 | 
			
		||||
  height: 100%;
 | 
			
		||||
  background: #F5F5F5;
 | 
			
		||||
 | 
			
		||||
  .error {
 | 
			
		||||
    font-size: 32px;
 | 
			
		||||
    color: #666;
 | 
			
		||||
    text-align: center;
 | 
			
		||||
    display: flex;
 | 
			
		||||
    flex-direction: column;
 | 
			
		||||
    align-items: center;
 | 
			
		||||
    justify-content: center;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ::v-deep .u-scroll-box {
 | 
			
		||||
    border-bottom: 1px solid #D4D4D4;
 | 
			
		||||
 | 
			
		||||
    .u-tab-bar {
 | 
			
		||||
      position: absolute;
 | 
			
		||||
      bottom: -6px;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ::v-deep .card {
 | 
			
		||||
    background: #fff;
 | 
			
		||||
    margin-bottom: 16px;
 | 
			
		||||
    padding: 16px 32px;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .half {
 | 
			
		||||
    width: 50%;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ::v-deep .tag {
 | 
			
		||||
    height: 56px;
 | 
			
		||||
    line-height: 56px;
 | 
			
		||||
    background: #F3F4F7;
 | 
			
		||||
    border-radius: 6px;
 | 
			
		||||
    padding: 8px 16px;
 | 
			
		||||
    margin-right: 16px;
 | 
			
		||||
    margin-bottom: 16px;
 | 
			
		||||
    overflow: hidden;
 | 
			
		||||
    cursor: default;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										146
									
								
								src/pages/resident/residentList.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,146 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <section class="residentList">
 | 
			
		||||
    <ai-top-fixed>
 | 
			
		||||
      <u-search placeholder="请输入昵称、姓名" :show-action="false" search-icon-color="#ccc"
 | 
			
		||||
                v-model="search.name" @search="page.current=1,getList()"/>
 | 
			
		||||
      <ai-cell>
 | 
			
		||||
        <b slot="label" class="title">共<i v-html="page.total||0"/>个居民</b>
 | 
			
		||||
      </ai-cell>
 | 
			
		||||
    </ai-top-fixed>
 | 
			
		||||
    <div class="mainPane">
 | 
			
		||||
      <ai-cell v-for="item in list" :key="item.id" @click.native="showResident(item)">
 | 
			
		||||
        <template #label>
 | 
			
		||||
          <ai-image :src="item.avatar" preview/>
 | 
			
		||||
        </template>
 | 
			
		||||
        <div class="card wrap start" flex>
 | 
			
		||||
          <b>{{ item.name }}</b>
 | 
			
		||||
          <div flex class="tag" v-for="(tag,j) in item.tags" :key="j">{{ tag.tagName }}</div>
 | 
			
		||||
          <div class="realName" shrink v-html="`真实姓名:${item.realName||'-'}`"/>
 | 
			
		||||
        </div>
 | 
			
		||||
      </ai-cell>
 | 
			
		||||
    </div>
 | 
			
		||||
  </section>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import AiCell from "../../components/AiCell";
 | 
			
		||||
import AiImage from "../../components/AiImage";
 | 
			
		||||
import AiTopFixed from "../../components/AiTopFixed";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: "residentList",
 | 
			
		||||
  components: {AiTopFixed, AiImage, AiCell},
 | 
			
		||||
  data() {
 | 
			
		||||
    return {
 | 
			
		||||
      page: {current: 1, size: 10, total: 0},
 | 
			
		||||
      search: {name: ""},
 | 
			
		||||
      list: []
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    getList() {
 | 
			
		||||
      this.$http.post("/app/wxcp/wxcustomer/list", null, {
 | 
			
		||||
        params: {...this.page, ...this.search, type: 1}
 | 
			
		||||
      }).then(res => {
 | 
			
		||||
        if (res?.data) {
 | 
			
		||||
          if (this.page.current > 1) {
 | 
			
		||||
            this.list = [...this.list, ...res.data.records]
 | 
			
		||||
          } else this.list = res.data.records
 | 
			
		||||
          this.page.total = res.data.total
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
    reachBottom() {
 | 
			
		||||
      if (this.page.total > this.list.length) {
 | 
			
		||||
        this.page.current++
 | 
			
		||||
        this.getList()
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    showResident({id}) {
 | 
			
		||||
      id && uni.navigateTo({
 | 
			
		||||
        url: './resident?id=' + id
 | 
			
		||||
      })
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  created() {
 | 
			
		||||
    this.getList()
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
.residentList {
 | 
			
		||||
  ::v-deep .AiTopFixed {
 | 
			
		||||
    b.title {
 | 
			
		||||
      color: #333;
 | 
			
		||||
      font-size: 32px;
 | 
			
		||||
 | 
			
		||||
      & > i {
 | 
			
		||||
        color: #267FCE;
 | 
			
		||||
        font-style: normal;
 | 
			
		||||
        margin: 0 4px;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ::v-deep .mainPane {
 | 
			
		||||
    background: #fff;
 | 
			
		||||
    padding: 0 32px;
 | 
			
		||||
 | 
			
		||||
    .AiCell {
 | 
			
		||||
      flex-shrink: 0;
 | 
			
		||||
      justify-content: flex-start;
 | 
			
		||||
 | 
			
		||||
      .content {
 | 
			
		||||
        flex: 1;
 | 
			
		||||
        min-width: 0;
 | 
			
		||||
        max-width: unset;
 | 
			
		||||
        border-bottom: 1px solid rgba(221, 221, 221, 1);
 | 
			
		||||
        min-height: 160px;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .card {
 | 
			
		||||
      text-align: left;
 | 
			
		||||
 | 
			
		||||
      b {
 | 
			
		||||
        max-width: 100%;
 | 
			
		||||
        white-space: nowrap;
 | 
			
		||||
        overflow: hidden;
 | 
			
		||||
        text-overflow: ellipsis;
 | 
			
		||||
        font-size: 36px;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .tag {
 | 
			
		||||
        justify-content: center;
 | 
			
		||||
        background: #F3F4F7;
 | 
			
		||||
        border-radius: 4px;
 | 
			
		||||
        padding: 0 16px;
 | 
			
		||||
        font-size: 28px;
 | 
			
		||||
        font-weight: 400;
 | 
			
		||||
        color: #333;
 | 
			
		||||
        margin-left: 16px;
 | 
			
		||||
        margin-bottom: 16px;
 | 
			
		||||
        height: 56px;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .realName {
 | 
			
		||||
        width: 100%;
 | 
			
		||||
        margin-top: 8px;
 | 
			
		||||
        font-size: 28px;
 | 
			
		||||
        font-weight: 400;
 | 
			
		||||
        color: #999;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .AiImage {
 | 
			
		||||
      margin-right: 24px;
 | 
			
		||||
 | 
			
		||||
      image {
 | 
			
		||||
        width: 112px;
 | 
			
		||||
        height: 112px;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										258
									
								
								src/pages/resident/residentSta.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,258 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="resident-statistical">
 | 
			
		||||
    <u-tabs :list="tabs" :is-scroll="false" :current="currentType" font-size="32"
 | 
			
		||||
            bar-width="192" height="96" bg-color="#3975C6"
 | 
			
		||||
            active-color="#fff" inactive-color="#fff" @change="handleChange"/>
 | 
			
		||||
    <div class="bg" :style="{backgroundImage:'url(' + $cdn + 'dvcp_bg.png' + ')'}"></div>
 | 
			
		||||
    <div class="card">
 | 
			
		||||
      <u-row justify="between">
 | 
			
		||||
        <div class="item" v-for="(item,index) in cardList" :key="index">
 | 
			
		||||
          <span :style="{color:item.color} ">{{ item.value }}</span>
 | 
			
		||||
          <span>{{ item.label }}</span>
 | 
			
		||||
        </div>
 | 
			
		||||
      </u-row>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="chart">
 | 
			
		||||
      <div id="chart"></div>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import echarts from "echarts"
 | 
			
		||||
import {mapActions} from "vuex";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: "residentSta",
 | 
			
		||||
  props: {
 | 
			
		||||
    isNormal: Boolean
 | 
			
		||||
  },
 | 
			
		||||
  data() {
 | 
			
		||||
    return {
 | 
			
		||||
      currentType: 0,
 | 
			
		||||
      groupId: null,
 | 
			
		||||
      chart: null,
 | 
			
		||||
      chartData: null
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    ...mapActions(['injectJWeixin', "wxInvoke"]),
 | 
			
		||||
    handleChange(i) {
 | 
			
		||||
      this.currentType = i
 | 
			
		||||
      this.getChart()
 | 
			
		||||
    },
 | 
			
		||||
    getChart() {
 | 
			
		||||
      this.$http.post(this.currentType == 0 ? "/app/wxcp/wxgroup/groupStatistic" : "/app/wxcp/wxcustomerlog/customerStatistic", null, {
 | 
			
		||||
        params: {
 | 
			
		||||
          id: this.groupId
 | 
			
		||||
        }
 | 
			
		||||
      }).then(res => {
 | 
			
		||||
        if (res.code == 0) {
 | 
			
		||||
          this.chartData = res.data
 | 
			
		||||
          this.initChart()
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
    initChart() {
 | 
			
		||||
      this.chart = echarts.init(document.getElementById('chart'))
 | 
			
		||||
      this.setOptions()
 | 
			
		||||
    },
 | 
			
		||||
    setOptions() {
 | 
			
		||||
      const x = Object.keys(this.chartData.list)
 | 
			
		||||
      const y = Object.values(this.chartData.list)
 | 
			
		||||
      this.chart.setOption({
 | 
			
		||||
        backgroundColor: "#F9F9F9",
 | 
			
		||||
        legend: {
 | 
			
		||||
          data: this.currentType == 0 ? ["群成员总数", "入群人数", "退群人数"] : ["居民总数", "新增居民数", "流失居民数"],
 | 
			
		||||
          icon: "rect",
 | 
			
		||||
          itemWidth: 8,
 | 
			
		||||
          itemHeight: 8,
 | 
			
		||||
          itemGap: 10,
 | 
			
		||||
          textStyle: {
 | 
			
		||||
            fontSize: 14,
 | 
			
		||||
            color: "#666666",
 | 
			
		||||
            lineHeight: 20
 | 
			
		||||
          },
 | 
			
		||||
          bottom: 0
 | 
			
		||||
        },
 | 
			
		||||
        grid: {
 | 
			
		||||
          left: 60,
 | 
			
		||||
          top: "10%",
 | 
			
		||||
          bottom: "30%",
 | 
			
		||||
        },
 | 
			
		||||
        xAxis: {
 | 
			
		||||
          axisTick: {
 | 
			
		||||
            show: false
 | 
			
		||||
          },
 | 
			
		||||
          axisLine: {
 | 
			
		||||
            show: false
 | 
			
		||||
          },
 | 
			
		||||
          axisLabel: {
 | 
			
		||||
            marginTop: 10,
 | 
			
		||||
            rotate: 40,
 | 
			
		||||
            textStyle: {
 | 
			
		||||
              fontSize: 12,
 | 
			
		||||
              color: '#666666'
 | 
			
		||||
            }
 | 
			
		||||
          },
 | 
			
		||||
          data: x.map(e => e.slice(5))
 | 
			
		||||
        },
 | 
			
		||||
        yAxis: {
 | 
			
		||||
          axisTick: {
 | 
			
		||||
            show: false
 | 
			
		||||
          },
 | 
			
		||||
          axisLine: {
 | 
			
		||||
            show: false
 | 
			
		||||
          },
 | 
			
		||||
          axisLabel: {
 | 
			
		||||
            textStyle: {
 | 
			
		||||
              fontSize: 12,
 | 
			
		||||
              color: '#666666'
 | 
			
		||||
            }
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
        series: [
 | 
			
		||||
          {
 | 
			
		||||
            name: this.currentType == 0 ? "群成员总数" : "居民总数",
 | 
			
		||||
            type: "line",
 | 
			
		||||
            itemStyle: {
 | 
			
		||||
              color: "#4B87FE"
 | 
			
		||||
            },
 | 
			
		||||
            data: y.map(e => e.total)
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            name: this.currentType == 0 ? "入群人数" : "新增居民数",
 | 
			
		||||
            type: "line",
 | 
			
		||||
            itemStyle: {
 | 
			
		||||
              color: "#32C5FF"
 | 
			
		||||
            },
 | 
			
		||||
            data: y.map(e => e.increase)
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            name: this.currentType == 0 ? "退群人数" : "流失居民数",
 | 
			
		||||
            type: "line",
 | 
			
		||||
            itemStyle: {
 | 
			
		||||
              color: "#FFAA44"
 | 
			
		||||
            },
 | 
			
		||||
            data: y.map(e => e.decrease)
 | 
			
		||||
          }
 | 
			
		||||
        ]
 | 
			
		||||
      })
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  computed: {
 | 
			
		||||
    tabs() {
 | 
			
		||||
      return [
 | 
			
		||||
        {name: "居民群统计", value: 0},
 | 
			
		||||
        {name: "居民统计", value: 1},
 | 
			
		||||
      ]
 | 
			
		||||
    },
 | 
			
		||||
    currentTab() {
 | 
			
		||||
      return this.tabs.find(e => e.value == this.currentType)
 | 
			
		||||
    },
 | 
			
		||||
    cardList() {
 | 
			
		||||
      return this.currentType == 0 ? [
 | 
			
		||||
        {label: "群聊总数", value: this.chartData?.groupSum || "0", color: "#354FC7"},
 | 
			
		||||
        {label: "群成员总数", value: this.chartData?.today?.total || "0", color: "#868686"},
 | 
			
		||||
        {label: "今日入群", value: this.chartData?.today?.increase || "0", color: "#5FBA95"},
 | 
			
		||||
        {label: "今日退群", value: this.chartData?.today?.decrease || "0", color: "#F09535"},
 | 
			
		||||
      ] : [
 | 
			
		||||
        {label: "居民总数", value: this.chartData?.today?.total || "0", color: "#354FC7"},
 | 
			
		||||
        {label: "今日新增", value: this.chartData?.today?.increase || "0", color: "#5FBA95"},
 | 
			
		||||
        {label: "今日流失", value: this.chartData?.today?.decrease || "0", color: "#F09535"},
 | 
			
		||||
      ]
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  watch: {
 | 
			
		||||
    isNormal(v) {
 | 
			
		||||
      v && this.getChart()
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  created() {
 | 
			
		||||
    if (this.$route.hash == "#dev") {
 | 
			
		||||
      this.getChart()
 | 
			
		||||
    } else this.injectJWeixin("getCurExternalChat").then(() => {
 | 
			
		||||
      return Promise.resolve()
 | 
			
		||||
    }).then(() => {
 | 
			
		||||
      this.wxInvoke(['getCurExternalChat', {}, res => {
 | 
			
		||||
        if (res?.err_msg == 'getCurExternalChat:ok') {
 | 
			
		||||
          this.groupId = res.chatId
 | 
			
		||||
        }
 | 
			
		||||
        this.getChart()
 | 
			
		||||
      }])
 | 
			
		||||
    })
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
.resident-statistical {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-direction: column;
 | 
			
		||||
  background: #F5F5F5;
 | 
			
		||||
  padding-top: 96px;
 | 
			
		||||
 | 
			
		||||
  ::v-deep .u-tabs {
 | 
			
		||||
    position: fixed;
 | 
			
		||||
    top: 0;
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    z-index: 9;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .bg {
 | 
			
		||||
    height: 340px;
 | 
			
		||||
    background-repeat: no-repeat;
 | 
			
		||||
    background-size: 100% 100%;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .card {
 | 
			
		||||
    width: 686px;
 | 
			
		||||
    height: 232px;
 | 
			
		||||
    margin: -140px auto 0;
 | 
			
		||||
    background-color: #FFFFFF;
 | 
			
		||||
    border-radius: 8px;
 | 
			
		||||
    display: flex;
 | 
			
		||||
    align-items: center;
 | 
			
		||||
    box-sizing: border-box;
 | 
			
		||||
    padding: 32px;
 | 
			
		||||
 | 
			
		||||
    .u-row {
 | 
			
		||||
      width: 100%;
 | 
			
		||||
 | 
			
		||||
      .item {
 | 
			
		||||
        flex: 1;
 | 
			
		||||
        text-align: center;
 | 
			
		||||
        font-size: 40px;
 | 
			
		||||
        font-weight: bold;
 | 
			
		||||
        color: #354FC7;
 | 
			
		||||
 | 
			
		||||
        & > span {
 | 
			
		||||
          display: block;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        & > span:last-child {
 | 
			
		||||
          font-size: 30px;
 | 
			
		||||
          font-weight: 500;
 | 
			
		||||
          color: #999999;
 | 
			
		||||
          line-height: 42px;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .chart {
 | 
			
		||||
    background-color: #FFFFFF;
 | 
			
		||||
    margin: 24px 0;
 | 
			
		||||
    box-sizing: border-box;
 | 
			
		||||
    padding: 32px;
 | 
			
		||||
    display: flex;
 | 
			
		||||
    justify-content: center;
 | 
			
		||||
    align-items: center;
 | 
			
		||||
 | 
			
		||||
    #chart {
 | 
			
		||||
      width: 686px;
 | 
			
		||||
      height: 470px;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										94
									
								
								src/pages/resident/tagManage.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,94 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <section class="tagManage">
 | 
			
		||||
    <div class="card" v-for="(group,i) in tags" :key="i">
 | 
			
		||||
      <ai-cell title :label="group.name"/>
 | 
			
		||||
      <u-row>
 | 
			
		||||
        <div class="tag" v-for="(op,j) in group.tagList" :key="j" :class="{selected:selected.includes(op.id)}"
 | 
			
		||||
             @tap="$u.debounce(handleToggle(op.id))">
 | 
			
		||||
          {{ op.name }}
 | 
			
		||||
        </div>
 | 
			
		||||
      </u-row>
 | 
			
		||||
    </div>
 | 
			
		||||
    <ai-back custom @back="top.showTagManage=false"/>
 | 
			
		||||
  </section>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import AiCell from "../../components/AiCell";
 | 
			
		||||
import UButton from "../../uview/components/u-button/u-button";
 | 
			
		||||
import ULoadingPage from "../../uview/components/u-loading-page/u-loading-page";
 | 
			
		||||
import AiBack from "../../components/AiBack";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: "tagManage",
 | 
			
		||||
  inject: ['top'],
 | 
			
		||||
  components: {AiBack, ULoadingPage, UButton, AiCell},
 | 
			
		||||
  data() {
 | 
			
		||||
    return {
 | 
			
		||||
      tags: []
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  computed: {
 | 
			
		||||
    selected() {
 | 
			
		||||
      return this.top.groupId ? this.top.detail?.tagList.map(e => e.tagId) : this.top.detail?.tags.map(e => e.tagId)
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    getTags() {
 | 
			
		||||
      this.$http.post(this.top.groupId ? "/app/wxcp/wxgroupchattag/listAll" : "/app/wxcp/wxcorptag/listAll", null, {
 | 
			
		||||
        params: {size: 9999}
 | 
			
		||||
      }).then(res => {
 | 
			
		||||
        if (res?.data) {
 | 
			
		||||
          this.tags = res.data.records
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
    handleToggle(tagId) {
 | 
			
		||||
      uni.showLoading({
 | 
			
		||||
        title: '提交中'
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      this.$http.post(this.top.groupId ? "/app/wxcp/wxgroupchattag/markTagForCP" : "/app/wxcp/wxcorptag/markTagForCP", null, {
 | 
			
		||||
        params: this.top.groupId ? {tagId, groupId: this.top.groupId,} : {tagId, customerId: this.top.custom}
 | 
			
		||||
      }).then(res => {
 | 
			
		||||
        uni.hideLoading()
 | 
			
		||||
        if (res?.code == 0) {
 | 
			
		||||
          this.$u.toast("操作成功!")
 | 
			
		||||
          this.getTags()
 | 
			
		||||
          this.top.getContact()
 | 
			
		||||
        }
 | 
			
		||||
      }).catch(err => {
 | 
			
		||||
        uni.hideLoading()
 | 
			
		||||
        this.$u.toast(err)
 | 
			
		||||
      })
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  created() {
 | 
			
		||||
    this.getTags()
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
.tagManage {
 | 
			
		||||
  padding-top: 16px;
 | 
			
		||||
 | 
			
		||||
  .tag {
 | 
			
		||||
    cursor: pointer !important;
 | 
			
		||||
 | 
			
		||||
    &.selected {
 | 
			
		||||
      background-color: $uni-color-primary !important;
 | 
			
		||||
      color: #fff
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    &.disabled {
 | 
			
		||||
      color: #999;
 | 
			
		||||
      cursor: not-allowed;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    & + .tag {
 | 
			
		||||
      margin-left: 16px;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										192
									
								
								src/pages/resourcesManage/addPlay.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,192 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="addPlay">
 | 
			
		||||
    <div v-if="type == '1'">
 | 
			
		||||
      <div class="content">
 | 
			
		||||
        <div class="item">
 | 
			
		||||
          <div class="label">音频文件</div>
 | 
			
		||||
          <div class="value" @click="toRecord">
 | 
			
		||||
            <span class="color-999" :style="{ color: file ? '#333' : '' }">{{ file ? '已选择' : '请选择' }}</span>
 | 
			
		||||
            <img src="./img/right-img.png" alt="">
 | 
			
		||||
          </div>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="radio-content">
 | 
			
		||||
        <div class="title">素材标题</div>
 | 
			
		||||
        <textarea rows="2" placeholder="请输入(30字以内)" v-model="name" style="width:100%;height:80px;" maxlength="30"></textarea>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div v-else>
 | 
			
		||||
      <div class="radio-content mar-b16">
 | 
			
		||||
        <div class="title">素材标题</div>
 | 
			
		||||
        <textarea rows="2" placeholder="请输入(30字以内)" v-model="name" style="width:100%;height:80px;" maxlength="30"></textarea>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="radio-content">
 | 
			
		||||
        <div class="title">文本内容</div>
 | 
			
		||||
        <textarea rows="8" placeholder="请输入文本内容(12000字以内)" v-model="content" style="width:100%;height:300px;" maxlength="12000"></textarea>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="btn" @click="confirm">确认</div>
 | 
			
		||||
    <AiBack></AiBack>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
  import AiBack from "@/components/AiBack";
 | 
			
		||||
  export default {
 | 
			
		||||
    name: "addPlay",
 | 
			
		||||
    data() {
 | 
			
		||||
      return {
 | 
			
		||||
        type: '1',
 | 
			
		||||
        file: null,
 | 
			
		||||
        name: '',
 | 
			
		||||
        content: ''
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    components: {
 | 
			
		||||
      AiBack
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    onLoad (query) {
 | 
			
		||||
      this.type = query.type
 | 
			
		||||
      uni.$on('record', e => {
 | 
			
		||||
        this.file = e
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    methods: {
 | 
			
		||||
      toRecord () {
 | 
			
		||||
        uni.navigateTo({
 | 
			
		||||
          url: `/pages/resourcesManage/recording`
 | 
			
		||||
        })
 | 
			
		||||
      },
 | 
			
		||||
 | 
			
		||||
      dataURLtoFile (dataurl, filename) {
 | 
			
		||||
        var arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1]
 | 
			
		||||
        var bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n)
 | 
			
		||||
 | 
			
		||||
        while (n--){
 | 
			
		||||
          u8arr[n] = bstr.charCodeAt(n)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return new File([u8arr], filename, {type:mime})
 | 
			
		||||
      },
 | 
			
		||||
 | 
			
		||||
      confirm () {
 | 
			
		||||
        if (!this.file && this.type === '1') {
 | 
			
		||||
          return this.$u.toast('请选择音频文件')
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!this.name) {
 | 
			
		||||
          return this.$u.toast('请输入素材标题')
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!this.content && this.type === '3') {
 | 
			
		||||
          return this.$u.toast('请输入文本内容')
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        uni.showLoading()
 | 
			
		||||
        let formData = {}
 | 
			
		||||
        formData = new FormData()
 | 
			
		||||
        if (this.type === '1') {
 | 
			
		||||
          formData.append('file', this.dataURLtoFile(this.file, this.name + '.mp3'))
 | 
			
		||||
          formData.append('type', this.type)
 | 
			
		||||
          formData.append('content', this.content)
 | 
			
		||||
          formData.append('name', this.name)
 | 
			
		||||
        } else {
 | 
			
		||||
          formData.append('type', this.type)
 | 
			
		||||
          formData.append('content', this.content)
 | 
			
		||||
          formData.append('name', this.name)
 | 
			
		||||
        }
 | 
			
		||||
        this.$http.post(`/app/appdlbresource/addResourceWithFile`, formData).then((res) => {
 | 
			
		||||
          uni.hideLoading()
 | 
			
		||||
          if (res.code === 0) {
 | 
			
		||||
            this.$u.toast('添加成功')
 | 
			
		||||
            uni.$emit('getList')
 | 
			
		||||
            uni.navigateBack({
 | 
			
		||||
              delta: 1
 | 
			
		||||
            })
 | 
			
		||||
          }
 | 
			
		||||
        }).catch(res => {
 | 
			
		||||
          this.$u.toast(res)
 | 
			
		||||
          uni.hideLoading()
 | 
			
		||||
        })
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
</script>
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
.addPlay {
 | 
			
		||||
  padding-bottom: 128px;
 | 
			
		||||
  .content{
 | 
			
		||||
    padding-left: 32px;
 | 
			
		||||
    background-color: #fff;
 | 
			
		||||
    .item{
 | 
			
		||||
      width: 100%;
 | 
			
		||||
      padding: 34px 0;
 | 
			
		||||
      font-size: 32px;
 | 
			
		||||
      font-family: PingFangSC-Regular, PingFang SC;
 | 
			
		||||
      font-weight: 400;
 | 
			
		||||
      line-height: 44px;
 | 
			
		||||
      border-bottom: 1px solid #ddd;
 | 
			
		||||
      display: flex;
 | 
			
		||||
      color: #333;
 | 
			
		||||
      justify-content: space-between;
 | 
			
		||||
      .label{
 | 
			
		||||
        width: 198px;
 | 
			
		||||
        font-size: 32px;
 | 
			
		||||
      }
 | 
			
		||||
      .value{
 | 
			
		||||
        font-size: 28px;
 | 
			
		||||
        width: calc(100% - 198px);
 | 
			
		||||
        padding-right: 32px;
 | 
			
		||||
        box-sizing: border-box;
 | 
			
		||||
        text-align: right;
 | 
			
		||||
 | 
			
		||||
        img{
 | 
			
		||||
          width: 32px;
 | 
			
		||||
          height: 32px;
 | 
			
		||||
          vertical-align: middle;
 | 
			
		||||
          margin-left: 6px;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      .color-999{
 | 
			
		||||
        color: #999;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  .radio-content{
 | 
			
		||||
    padding: 34px 32px 38px;
 | 
			
		||||
    background-color: #fff;
 | 
			
		||||
    .title{
 | 
			
		||||
      font-size: 32px;
 | 
			
		||||
      font-family: PingFangSC-Regular, PingFang SC;
 | 
			
		||||
      font-weight: 400;
 | 
			
		||||
      color: #333;
 | 
			
		||||
      line-height: 44px;
 | 
			
		||||
      margin-bottom: 32px;
 | 
			
		||||
      span{
 | 
			
		||||
        font-size: 24px;
 | 
			
		||||
        font-weight: 400;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  .mar-b16{
 | 
			
		||||
    margin-bottom: 16px;
 | 
			
		||||
  }
 | 
			
		||||
  .btn{
 | 
			
		||||
    position: fixed;
 | 
			
		||||
    bottom: 0;
 | 
			
		||||
    left: 0;
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    height: 112px;
 | 
			
		||||
    line-height: 112px;
 | 
			
		||||
    text-align: center;
 | 
			
		||||
    background: #3975C6;
 | 
			
		||||
    font-size: 32px;
 | 
			
		||||
    font-family: PingFangSC-Medium, PingFang SC;
 | 
			
		||||
    font-weight: 500;
 | 
			
		||||
    color: #FFFFFF;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								src/pages/resourcesManage/img/add-icon.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 6.1 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								src/pages/resourcesManage/img/body.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 14 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								src/pages/resourcesManage/img/microphone.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 4.7 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								src/pages/resourcesManage/img/play-icon.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 4.1 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								src/pages/resourcesManage/img/right-icon.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 269 B  | 
							
								
								
									
										
											BIN
										
									
								
								src/pages/resourcesManage/img/right-img.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 269 B  | 
							
								
								
									
										
											BIN
										
									
								
								src/pages/resourcesManage/img/stop-img.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 3.6 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								src/pages/resourcesManage/img/top.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 531 B  | 
							
								
								
									
										
											BIN
										
									
								
								src/pages/resourcesManage/img/video-img.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 577 B  | 
							
								
								
									
										540
									
								
								src/pages/resourcesManage/recording.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,540 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="recording">
 | 
			
		||||
    <div class="recording-content" v-if="isRecording">
 | 
			
		||||
      <div class="header-top" :style="{width: progress + '%'}"></div>
 | 
			
		||||
      <div class="header-line" :style="{width: progress + '%'}">
 | 
			
		||||
        <span class="line1 animation"></span>
 | 
			
		||||
        <span class="line2 animation"></span>
 | 
			
		||||
        <span class="line3 animation"></span>
 | 
			
		||||
        <span class="line4 animation"></span>
 | 
			
		||||
        <span class="line5 animation"></span>
 | 
			
		||||
        <span class="line6 animation"></span>
 | 
			
		||||
        <span class="line7 animation"></span>
 | 
			
		||||
        <span class="line8 animation"></span>
 | 
			
		||||
        <span class="line9 animation"></span>
 | 
			
		||||
        <span class="line10 animation"></span>
 | 
			
		||||
        <span class="line11 animation"></span>
 | 
			
		||||
        <span class="line12 animation"></span>
 | 
			
		||||
        <span class="line13 animation"></span>
 | 
			
		||||
        <span class="line14 animation"></span>
 | 
			
		||||
        <span class="line15 animation"></span>
 | 
			
		||||
        <span class="line16 animation"></span>
 | 
			
		||||
        <span class="line17 animation"></span>
 | 
			
		||||
        <span class="line18 animation"></span>
 | 
			
		||||
        <span class="line19 animation"></span>
 | 
			
		||||
        <span class="line20 animation"></span>
 | 
			
		||||
        <span class="line1 animation"></span>
 | 
			
		||||
        <span class="line2 animation"></span>
 | 
			
		||||
        <span class="line3 animation"></span>
 | 
			
		||||
        <span class="line4 animation"></span>
 | 
			
		||||
        <span class="line5 animation"></span>
 | 
			
		||||
        <span class="line6 animation"></span>
 | 
			
		||||
        <span class="line7 animation"></span>
 | 
			
		||||
        <span class="line8 animation"></span>
 | 
			
		||||
        <span class="line9 animation"></span>
 | 
			
		||||
        <span class="line10 animation"></span>
 | 
			
		||||
        <span class="line11 animation"></span>
 | 
			
		||||
        <span class="line12 animation"></span>
 | 
			
		||||
        <span class="line13 animation"></span>
 | 
			
		||||
        <span class="line14 animation"></span>
 | 
			
		||||
        <span class="line15 animation"></span>
 | 
			
		||||
        <span class="line16 animation"></span>
 | 
			
		||||
        <span class="line17 animation"></span>
 | 
			
		||||
        <span class="line18 animation"></span>
 | 
			
		||||
        <span class="line19 animation"></span>
 | 
			
		||||
        <span class="line20 animation"></span>
 | 
			
		||||
        <span class="line1 animation"></span>
 | 
			
		||||
        <span class="line2 animation"></span>
 | 
			
		||||
        <span class="line3 animation"></span>
 | 
			
		||||
        <span class="line4 animation"></span>
 | 
			
		||||
        <span class="line5 animation"></span>
 | 
			
		||||
        <span class="line6 animation"></span>
 | 
			
		||||
        <span class="line7 animation"></span>
 | 
			
		||||
        <span class="line8 animation"></span>
 | 
			
		||||
        <span class="line9 animation"></span>
 | 
			
		||||
        <span class="line10 animation"></span>
 | 
			
		||||
        <span class="line10 animation"></span>
 | 
			
		||||
        <span class="line11 animation"></span>
 | 
			
		||||
        <span class="line12 animation"></span>
 | 
			
		||||
        <span class="line13 animation"></span>
 | 
			
		||||
        <span class="line14 animation"></span>
 | 
			
		||||
        <span class="line15 animation"></span>
 | 
			
		||||
        <span class="line16 animation"></span>
 | 
			
		||||
        <span class="line17 animation"></span>
 | 
			
		||||
        <span class="line18 animation"></span>
 | 
			
		||||
        <span class="line19 animation"></span>
 | 
			
		||||
        <span class="line20 animation"></span>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="progress" :style="{left: progress + '%'}"></div>
 | 
			
		||||
      <p class="time">{{ time }}</p>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="stop-content" v-else-if="!isRecording && isStop">
 | 
			
		||||
      <p class="time">{{ time }}</p>
 | 
			
		||||
      <div class="header-line">
 | 
			
		||||
        <span class="line1 animation"></span>
 | 
			
		||||
        <span class="line2 animation"></span>
 | 
			
		||||
        <span class="line3 animation"></span>
 | 
			
		||||
        <span class="line4 animation"></span>
 | 
			
		||||
        <span class="line5 animation"></span>
 | 
			
		||||
        <span class="line6 animation"></span>
 | 
			
		||||
        <span class="line7 animation"></span>
 | 
			
		||||
        <span class="line8 animation"></span>
 | 
			
		||||
        <span class="line9 animation"></span>
 | 
			
		||||
        <span class="line10 animation"></span>
 | 
			
		||||
        <span class="line11 animation"></span>
 | 
			
		||||
        <span class="line12 animation"></span>
 | 
			
		||||
        <span class="line13 animation"></span>
 | 
			
		||||
        <span class="line14 animation"></span>
 | 
			
		||||
        <span class="line15 animation"></span>
 | 
			
		||||
        <span class="line16 animation"></span>
 | 
			
		||||
        <span class="line17 animation"></span>
 | 
			
		||||
        <span class="line18 animation"></span>
 | 
			
		||||
        <span class="line19 animation"></span>
 | 
			
		||||
        <span class="line20 animation"></span>
 | 
			
		||||
        <span class="line1 animation"></span>
 | 
			
		||||
        <span class="line2 animation"></span>
 | 
			
		||||
        <span class="line3 animation"></span>
 | 
			
		||||
        <span class="line4 animation"></span>
 | 
			
		||||
        <span class="line5 animation"></span>
 | 
			
		||||
        <span class="line6 animation"></span>
 | 
			
		||||
        <span class="line7 animation"></span>
 | 
			
		||||
        <span class="line8 animation"></span>
 | 
			
		||||
        <span class="line9 animation"></span>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="content" v-else>
 | 
			
		||||
      <img src="./img/body.png" alt="">
 | 
			
		||||
      <p class="text">点击下方按钮开始录音</p>
 | 
			
		||||
      <p class="text">为了保证效果,请靠近手机讲话哦~</p>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="footer">
 | 
			
		||||
      <span v-if="isRecording || isStop" @click="restart">重新开始</span>
 | 
			
		||||
      <img v-if="isStop" :src="!isPlay ? playImg : stopImg" @click="play">
 | 
			
		||||
      <img v-else :src="isRecording ? stopImg : microphone" @click="record">
 | 
			
		||||
      <span v-if="isStop" @click="save">保存</span>
 | 
			
		||||
    </div>
 | 
			
		||||
    <AiBack></AiBack>
 | 
			
		||||
    <audio style="opacity: 0; visibility: hidden;" :src="audioSrc" @ended="onAudioEnd"></audio>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script> 
 | 
			
		||||
  import AiBack from "@/components/AiBack";
 | 
			
		||||
  import Recorder from 'recorder-core'
 | 
			
		||||
  import 'recorder-core/src/engine/mp3'
 | 
			
		||||
  import 'recorder-core/src/engine/mp3-engine'
 | 
			
		||||
  import stopImg from './img/stop-img.png'
 | 
			
		||||
  import microphone from './img/microphone.png'
 | 
			
		||||
  import playImg from './img/play-icon.png'
 | 
			
		||||
 | 
			
		||||
  export default {
 | 
			
		||||
    name: 'recording',
 | 
			
		||||
    data () {
 | 
			
		||||
      return {
 | 
			
		||||
        isRecording: false,
 | 
			
		||||
        progress: 0,
 | 
			
		||||
        microphone,
 | 
			
		||||
        playImg,
 | 
			
		||||
        stopImg,
 | 
			
		||||
        isPlay: false,
 | 
			
		||||
        isStop: false,
 | 
			
		||||
        blobFile: null,
 | 
			
		||||
        time: '00:00:00',
 | 
			
		||||
        counterDownTime: 0,
 | 
			
		||||
        recorder: null,
 | 
			
		||||
        counterDownTimeout: null,
 | 
			
		||||
        timingTimeout: null,
 | 
			
		||||
        audioSrc: '',
 | 
			
		||||
        audio: null,
 | 
			
		||||
        duration: 0
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    components: {
 | 
			
		||||
      AiBack
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    mounted () {
 | 
			
		||||
      this.$nextTick(() => {
 | 
			
		||||
        this.audio = document.querySelector('audio')
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    methods: {
 | 
			
		||||
      record () {
 | 
			
		||||
        if (!this.isRecording) {
 | 
			
		||||
          this.duration = 0
 | 
			
		||||
          this.recorder = Recorder({
 | 
			
		||||
            type: 'mp3',
 | 
			
		||||
            sampleRate: 16000,
 | 
			
		||||
            bitRate: 16,
 | 
			
		||||
            onProcess (buffers, powerLevel, bufferDuration, bufferSampleRate, newBufferIdx, asyncEnd) {
 | 
			
		||||
              //可利用extensions/waveview.js扩展实时绘制波形
 | 
			
		||||
            }
 | 
			
		||||
          })
 | 
			
		||||
 | 
			
		||||
          this.recorder.open(() => {
 | 
			
		||||
            this.recorder.start()
 | 
			
		||||
            this.isRecording = true
 | 
			
		||||
            this.timing()
 | 
			
		||||
          }, (msg, isUserNotAllow) => {
 | 
			
		||||
            // this.$u.toast(`${isUserNotAllow ? '请同意授权' : msg}`)
 | 
			
		||||
          })
 | 
			
		||||
        } else {
 | 
			
		||||
          this.stop()
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
 | 
			
		||||
      blobToDataURI (blob) {
 | 
			
		||||
        return new Promise((resolve) => {
 | 
			
		||||
          var reader = new FileReader()
 | 
			
		||||
          reader.readAsDataURL(blob)
 | 
			
		||||
          reader.onload = function (e) {
 | 
			
		||||
            resolve(e.target.result)
 | 
			
		||||
          }
 | 
			
		||||
        })
 | 
			
		||||
      },
 | 
			
		||||
 | 
			
		||||
      save () {
 | 
			
		||||
        if (!this.blobFile) {
 | 
			
		||||
          return this.$u.toast(`请录音`)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.blobToDataURI(this.blobFile).then(res => {
 | 
			
		||||
          uni.$emit('record', res)
 | 
			
		||||
          uni.navigateBack({
 | 
			
		||||
            delta: 1
 | 
			
		||||
          })
 | 
			
		||||
        })
 | 
			
		||||
      },
 | 
			
		||||
 | 
			
		||||
      onAudioEnd () {
 | 
			
		||||
        this.isPlay = false
 | 
			
		||||
      },
 | 
			
		||||
 | 
			
		||||
      stop () {
 | 
			
		||||
        this.isRecording = false
 | 
			
		||||
        this.isStop = true
 | 
			
		||||
        clearTimeout(this.timingTimeout)
 | 
			
		||||
        this.recorder.stop((blob, duration) => {
 | 
			
		||||
          this.blobFile = blob
 | 
			
		||||
          
 | 
			
		||||
          var durationObj = this.$dayjs.duration(this.counterDownTime * 1000)
 | 
			
		||||
          this.duration = this.counterDownTime
 | 
			
		||||
          var hours = durationObj.hours() > 9 ? durationObj.hours() : '0' + durationObj.hours()
 | 
			
		||||
          var min = durationObj.minutes() > 9 ? durationObj.minutes() : '0' + durationObj.minutes()
 | 
			
		||||
          var seconds = durationObj.seconds() > 9 ? durationObj.seconds() : '0' + durationObj.seconds()
 | 
			
		||||
 | 
			
		||||
          this.time = hours + ':' + min + ':' + seconds
 | 
			
		||||
          console.log(blob, (window.URL|| webkitURL).createObjectURL(blob), '时长:' + duration + 'ms')
 | 
			
		||||
          this.recorder.close()
 | 
			
		||||
          this.recorder = null
 | 
			
		||||
        }, msg => {
 | 
			
		||||
          console.log('录音失败:' + msg)
 | 
			
		||||
          this.recorder.close()
 | 
			
		||||
          this.recorder = null
 | 
			
		||||
        })
 | 
			
		||||
      },
 | 
			
		||||
 | 
			
		||||
      play () {
 | 
			
		||||
        if (!this.isPlay) {
 | 
			
		||||
          this.playAudio()
 | 
			
		||||
          this.counterDown()
 | 
			
		||||
        } else {
 | 
			
		||||
          this.isPlay = false
 | 
			
		||||
          clearTimeout(this.counterDownTimeout)
 | 
			
		||||
          this.audio.pause()
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
 | 
			
		||||
      playAudio () {
 | 
			
		||||
        this.isPlay = true
 | 
			
		||||
        if (!this.audioSrc) {
 | 
			
		||||
          this.audioSrc = (window.URL||webkitURL).createObjectURL(this.blobFile)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.$nextTick(() => {
 | 
			
		||||
          this.audio.play()
 | 
			
		||||
        })
 | 
			
		||||
      },
 | 
			
		||||
 | 
			
		||||
      recodeStop () {
 | 
			
		||||
        this.recorder.stop((blob, duration) => {
 | 
			
		||||
          this.restart()
 | 
			
		||||
          this.blobFile = blob
 | 
			
		||||
          console.log(blob, (window.URL|| webkitURL).createObjectURL(blob), '时长:' + duration + 'ms')
 | 
			
		||||
          this.recorder.close()
 | 
			
		||||
          this.recorder = null
 | 
			
		||||
        }, msg => {
 | 
			
		||||
          console.log('录音失败:' + msg)
 | 
			
		||||
          this.recorder.close()
 | 
			
		||||
          this.recorder = null
 | 
			
		||||
        })
 | 
			
		||||
      },
 | 
			
		||||
 | 
			
		||||
      restart () {
 | 
			
		||||
        this.time = '00:00:00'
 | 
			
		||||
        this.progress = 0
 | 
			
		||||
        this.blobFile = null
 | 
			
		||||
        this.isPlay = false
 | 
			
		||||
        this.isRecording = false
 | 
			
		||||
        clearTimeout(this.counterDownTimeout)
 | 
			
		||||
        clearTimeout(this.timingTimeout)
 | 
			
		||||
        this.counterDownTime = 0
 | 
			
		||||
        this.audioSrc = ''
 | 
			
		||||
        this.isStop = false
 | 
			
		||||
      },
 | 
			
		||||
 | 
			
		||||
      counterDown () {
 | 
			
		||||
        if (this.counterDownTime === -1) {
 | 
			
		||||
          clearTimeout(this.counterDownTimeout)
 | 
			
		||||
          this.counterDownTime = this.duration
 | 
			
		||||
 | 
			
		||||
          return false
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var durationObj = this.$dayjs.duration(this.counterDownTime * 1000)
 | 
			
		||||
        var hours = durationObj.hours() > 9 ? durationObj.hours() : '0' + durationObj.hours()
 | 
			
		||||
        var min = durationObj.minutes() > 9 ? durationObj.minutes() : '0' + durationObj.minutes()
 | 
			
		||||
        var seconds = durationObj.seconds() > 9 ? durationObj.seconds() : '0' + durationObj.seconds()
 | 
			
		||||
 | 
			
		||||
        this.time = hours + ':' + min + ':' + seconds
 | 
			
		||||
        this.counterDownTime --
 | 
			
		||||
        this.counterDownTimeout = setTimeout(() => {
 | 
			
		||||
          this.counterDown()
 | 
			
		||||
        }, 1000)
 | 
			
		||||
      },
 | 
			
		||||
 | 
			
		||||
      timing () {
 | 
			
		||||
        this.progress = ((this.counterDownTime / 120) * 100).toFixed(2) > 100 ? 101 : ((this.counterDownTime / 120) * 100).toFixed(2)
 | 
			
		||||
        var durationObj = this.$dayjs.duration(this.counterDownTime * 1000)
 | 
			
		||||
        var hours = durationObj.hours() > 9 ? durationObj.hours() : '0' + durationObj.hours()
 | 
			
		||||
        var min = durationObj.minutes() > 9 ? durationObj.minutes() : '0' + durationObj.minutes()
 | 
			
		||||
        var seconds = durationObj.seconds() > 9 ? durationObj.seconds() : '0' + durationObj.seconds()
 | 
			
		||||
 | 
			
		||||
        this.time = hours + ':' + min + ':' + seconds
 | 
			
		||||
        this.counterDownTime ++
 | 
			
		||||
        this.timingTimeout = setTimeout(() => {
 | 
			
		||||
          this.timing()
 | 
			
		||||
        }, 1000)
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
  uni-page-body{
 | 
			
		||||
    background-color: #fff;
 | 
			
		||||
  }
 | 
			
		||||
  .recording {
 | 
			
		||||
    height: 100vh;
 | 
			
		||||
    overflow-y: hidden;
 | 
			
		||||
 | 
			
		||||
    .content{
 | 
			
		||||
      padding-top: 310px;
 | 
			
		||||
      text-align: center;
 | 
			
		||||
      img{
 | 
			
		||||
        width: 406px;
 | 
			
		||||
        height: 306px;
 | 
			
		||||
        margin-bottom: 48px;
 | 
			
		||||
      }
 | 
			
		||||
      .text{
 | 
			
		||||
        font-size: 30px;
 | 
			
		||||
        color: #999;
 | 
			
		||||
        line-height: 42px;
 | 
			
		||||
        text-align: center;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    .footer{
 | 
			
		||||
      display: flex;
 | 
			
		||||
      align-items: center;
 | 
			
		||||
      justify-content: center;
 | 
			
		||||
      position: fixed;
 | 
			
		||||
      bottom: 0;
 | 
			
		||||
      left: 0;
 | 
			
		||||
      width: 100%;
 | 
			
		||||
      height: 168px;
 | 
			
		||||
      background: #F6F8FC;
 | 
			
		||||
      padding: 20px 86px;
 | 
			
		||||
      box-sizing: border-box;
 | 
			
		||||
      span{
 | 
			
		||||
        display: inline-block;
 | 
			
		||||
        width: 160px;
 | 
			
		||||
        height: 64px;
 | 
			
		||||
        background: #4E8EEE;
 | 
			
		||||
        border-radius: 32px;
 | 
			
		||||
        font-size: 30px;
 | 
			
		||||
        color: #fff;
 | 
			
		||||
        text-align: center;
 | 
			
		||||
        line-height: 64px;
 | 
			
		||||
        vertical-align: top;
 | 
			
		||||
        margin-top: 30px;
 | 
			
		||||
      }
 | 
			
		||||
      img{
 | 
			
		||||
        width: 128px;
 | 
			
		||||
        height: 128px;
 | 
			
		||||
        margin: 0 64px;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .recording-content {
 | 
			
		||||
      position: relative;
 | 
			
		||||
      overflow: hidden;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .stop-content {
 | 
			
		||||
      display: flex;
 | 
			
		||||
      align-items: center;
 | 
			
		||||
      justify-content: center;
 | 
			
		||||
      flex-direction: column;
 | 
			
		||||
      height: calc(100% - 168px);
 | 
			
		||||
 | 
			
		||||
      .header-line {
 | 
			
		||||
        width: 380px;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .time {
 | 
			
		||||
        margin-top: 0;
 | 
			
		||||
        margin-bottom: 32px;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .header-top {
 | 
			
		||||
      position: absolute;
 | 
			
		||||
      top: 16px;
 | 
			
		||||
      left: 0;
 | 
			
		||||
      height: 6px;
 | 
			
		||||
      background: url(./img/top.png) repeat-x;
 | 
			
		||||
      background-size: auto 6px;
 | 
			
		||||
    }
 | 
			
		||||
    .time{
 | 
			
		||||
      width: 100%;
 | 
			
		||||
      margin-top: 208px;
 | 
			
		||||
      text-align: center;
 | 
			
		||||
      font-size: 96px;
 | 
			
		||||
      color: #000000;
 | 
			
		||||
      line-height: 134px;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .progress {
 | 
			
		||||
      position: absolute;
 | 
			
		||||
      top: 16px;
 | 
			
		||||
      left: 0;
 | 
			
		||||
      width: 2px;
 | 
			
		||||
      height: 128px;
 | 
			
		||||
      background: #3477EE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .header-line {
 | 
			
		||||
      width: 100%;
 | 
			
		||||
      max-width: 100%;
 | 
			
		||||
      height: 128px;
 | 
			
		||||
      line-height: 128px;
 | 
			
		||||
      margin-top: 16px;
 | 
			
		||||
      overflow: hidden;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .animation {
 | 
			
		||||
      animation: note 0.24s ease-in-out;
 | 
			
		||||
      animation-iteration-count: infinite;
 | 
			
		||||
      animation-direction: alternate;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .header-line span {
 | 
			
		||||
      display: inline-block;
 | 
			
		||||
      width: 6px;
 | 
			
		||||
      height: 16px;
 | 
			
		||||
      margin: 0 6px;
 | 
			
		||||
      border: none;
 | 
			
		||||
      border-radius: 4px;
 | 
			
		||||
      background-color: #3476EE;
 | 
			
		||||
    }
 | 
			
		||||
    .header-line span.line1 {
 | 
			
		||||
      animation-delay: -1s;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .header-line span.line2 {
 | 
			
		||||
      animation-delay: -0.9s;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .header-line span.line3 {
 | 
			
		||||
      animation-delay: -0.8s;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .header-line span.line4 {
 | 
			
		||||
      animation-delay: -0.7s;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .header-line span.line5 {
 | 
			
		||||
      animation-delay: -0.6s;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .header-line span.line6 {
 | 
			
		||||
      animation-delay: -0.5s;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .header-line span.line7 {
 | 
			
		||||
      animation-delay: -0.4s;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .header-line span.line8 {
 | 
			
		||||
      animation-delay: -0.4s;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .header-line span.line9 {
 | 
			
		||||
      animation-delay: -0.2s;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .header-line span.line10 {
 | 
			
		||||
      animation-delay: -0.1s;
 | 
			
		||||
    }
 | 
			
		||||
    .header-line span.line11 {
 | 
			
		||||
      animation-delay: -1s;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .header-line span.line12 {
 | 
			
		||||
      animation-delay: -0.9s;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .header-line span.line13 {
 | 
			
		||||
      animation-delay: -0.8s;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .header-line span.line14 {
 | 
			
		||||
      animation-delay: -0.7s;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .header-line span.line15 {
 | 
			
		||||
      animation-delay: -0.6s;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .header-line span.line16 {
 | 
			
		||||
      animation-delay: -0.5s;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .header-line span.line17 {
 | 
			
		||||
      animation-delay: -0.4s;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .header-line span.line18 {
 | 
			
		||||
      animation-delay: -0.3s;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .header-line span.line19 {
 | 
			
		||||
      animation-delay: -0.2s;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .header-line span.line20 {
 | 
			
		||||
      animation-delay: -0.1s;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @keyframes note {
 | 
			
		||||
      from {
 | 
			
		||||
        transform: scaleY(1);
 | 
			
		||||
      }
 | 
			
		||||
      to {
 | 
			
		||||
        transform: scaleY(4);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										245
									
								
								src/pages/resourcesManage/resourcesManage.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,245 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="resourcesManage">
 | 
			
		||||
    <div class="tab">
 | 
			
		||||
      <u-tabs :list="tab" :is-scroll="false" :current="currIndex" @change="change" height="96" :bar-style="barStyle"></u-tabs>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="record" v-if="currIndex == 0">
 | 
			
		||||
      <div class="item" v-for="(item, index) in list" :key="index" @click="choose(item)">
 | 
			
		||||
        <img src="./img/play-icon.png" alt="">
 | 
			
		||||
        <div class="info">
 | 
			
		||||
          <p>{{ item.name ? item.name.split('.')[0] : '-' }}</p>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="record-text" v-else>
 | 
			
		||||
      <div class="item" v-for="(item, index) in list" :key="index" @click="choose(item)">
 | 
			
		||||
        <div>{{ item.name }}</div>
 | 
			
		||||
        <p>{{ item.content }}</p>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <img src="./img/add-icon.png" alt="" class="add-img" @click="add">
 | 
			
		||||
    <u-popup v-model="isShow" mode="bottom">
 | 
			
		||||
      <div class="audio">
 | 
			
		||||
        <AiVideo :src="url" autoplay></AiVideo>
 | 
			
		||||
			  <!-- <audio :src="url" ref="audio" :controls="true" :name="autioName" style="display: block;"></audio> -->
 | 
			
		||||
      </div>
 | 
			
		||||
		</u-popup>
 | 
			
		||||
    <AiBack></AiBack>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
<script> 
 | 
			
		||||
  import AiVideo from '@/components/AiVideo'
 | 
			
		||||
  import AiBack from "@/components/AiBack";
 | 
			
		||||
  export default {
 | 
			
		||||
    name: "resourcesManage",
 | 
			
		||||
    data() {
 | 
			
		||||
      return {
 | 
			
		||||
        tab: [{ name: '音频素材' }, { name: '文本素材' }],
 | 
			
		||||
        list: [],
 | 
			
		||||
        currIndex: 0,
 | 
			
		||||
        current: 1,
 | 
			
		||||
        isChoose: false,
 | 
			
		||||
        isMore: false,
 | 
			
		||||
        isShow: false,
 | 
			
		||||
        url: '',
 | 
			
		||||
        autioName: '',
 | 
			
		||||
        audio: null,
 | 
			
		||||
        barStyle: {width:'98px', bottom: '-3px', left: '-38px'}
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    components: {
 | 
			
		||||
      AiBack,
 | 
			
		||||
      AiVideo
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    onLoad (query) {
 | 
			
		||||
      this.isChoose = query.isChoose ? true : false
 | 
			
		||||
      this.getList()
 | 
			
		||||
      uni.$on('getList', e => {
 | 
			
		||||
        this.isMore = false
 | 
			
		||||
        this.list = []
 | 
			
		||||
        this.current = 1
 | 
			
		||||
 | 
			
		||||
        this.$nextTick(() => {
 | 
			
		||||
          this.getList()
 | 
			
		||||
        })
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    methods: {
 | 
			
		||||
      change(index) {
 | 
			
		||||
        this.isMore = false
 | 
			
		||||
        this.list = []
 | 
			
		||||
        this.current = 1
 | 
			
		||||
        this.currIndex = index
 | 
			
		||||
 | 
			
		||||
        this.$nextTick(() => {
 | 
			
		||||
          this.getList()
 | 
			
		||||
        })
 | 
			
		||||
      },
 | 
			
		||||
 | 
			
		||||
      add () {
 | 
			
		||||
        uni.navigateTo({
 | 
			
		||||
          url: `/pages/resourcesManage/addPlay?type=${this.currIndex === 0 ? 1 : 3}`
 | 
			
		||||
        })
 | 
			
		||||
      },
 | 
			
		||||
 | 
			
		||||
      choose (item) {
 | 
			
		||||
        if (!this.isChoose) {
 | 
			
		||||
          console.log(item.url)
 | 
			
		||||
          this.url = item.url
 | 
			
		||||
          this.isShow = true
 | 
			
		||||
 | 
			
		||||
          return false
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        uni.$emit('choose', {
 | 
			
		||||
          mediaId: item.id,
 | 
			
		||||
          mediaName: item.name
 | 
			
		||||
        })
 | 
			
		||||
        uni.navigateBack({
 | 
			
		||||
          delta: 1
 | 
			
		||||
        })
 | 
			
		||||
      },
 | 
			
		||||
 | 
			
		||||
      getList () {
 | 
			
		||||
        if (this.isMore) return
 | 
			
		||||
 | 
			
		||||
        this.$http.post(`/app/appdlbresource/list`, null, {
 | 
			
		||||
          params: {
 | 
			
		||||
            ...this.search,
 | 
			
		||||
            type: this.currIndex === 0 ? 1 : 3,
 | 
			
		||||
            current: this.current,
 | 
			
		||||
            size: 10
 | 
			
		||||
          }
 | 
			
		||||
        }).then(res => {
 | 
			
		||||
          if (res.code == 0) {
 | 
			
		||||
            if (this.current > 1) {
 | 
			
		||||
              this.list = [...this.list, ...res.data.records]
 | 
			
		||||
            } else {
 | 
			
		||||
              this.list = res.data.records
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            uni.hideLoading()
 | 
			
		||||
 | 
			
		||||
            if (res.data.records.length < 10) {
 | 
			
		||||
              this.isMore = true
 | 
			
		||||
 | 
			
		||||
              return false
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            this.current = this.current + 1
 | 
			
		||||
          } else {
 | 
			
		||||
            uni.hideLoading()
 | 
			
		||||
          }
 | 
			
		||||
        }).catch(() => {
 | 
			
		||||
          uni.hideLoading()
 | 
			
		||||
        })
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    onReachBottom() {
 | 
			
		||||
      this.getList()
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
</script>
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
.resourcesManage {
 | 
			
		||||
  padding-bottom: 128px;
 | 
			
		||||
  .tab{
 | 
			
		||||
    border-bottom: 1px solid #ddd;
 | 
			
		||||
    margin-bottom: 4px;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .audio {
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    height: 400rpx;
 | 
			
		||||
    box-sizing: border-box;
 | 
			
		||||
    padding: 104rpx 0 46rpx;
 | 
			
		||||
    audio {
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .record{
 | 
			
		||||
    background-color: #fff;
 | 
			
		||||
    .item{
 | 
			
		||||
      width: 100%;
 | 
			
		||||
      display: flex;
 | 
			
		||||
      border-bottom: 1px solid #ddd;
 | 
			
		||||
      padding: 32px 30px;
 | 
			
		||||
      box-sizing: border-box;
 | 
			
		||||
      img{
 | 
			
		||||
        width: 56px;
 | 
			
		||||
        height: 56px;
 | 
			
		||||
        margin-right: 14px;
 | 
			
		||||
      }
 | 
			
		||||
      .info{
 | 
			
		||||
        width: calc(100% - 70px);
 | 
			
		||||
        line-height: 44px;
 | 
			
		||||
        font-size: 34px;
 | 
			
		||||
        font-family: PingFang-SC-Medium, PingFang-SC;
 | 
			
		||||
        font-weight: 500;
 | 
			
		||||
        color: #333;
 | 
			
		||||
 | 
			
		||||
        p {
 | 
			
		||||
          overflow: hidden;
 | 
			
		||||
          text-overflow: ellipsis;
 | 
			
		||||
          white-space: nowrap;
 | 
			
		||||
          word-break: break-all;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  .record-text{
 | 
			
		||||
     background-color: #fff;
 | 
			
		||||
    .item{
 | 
			
		||||
      width: 100%;
 | 
			
		||||
      border-bottom: 1px solid #ddd;
 | 
			
		||||
      padding: 32px 30px;
 | 
			
		||||
      box-sizing: border-box;
 | 
			
		||||
      font-size: 30px;
 | 
			
		||||
      div{
 | 
			
		||||
        font-size: 30px;
 | 
			
		||||
        font-family: PingFangSC-Medium, PingFang SC;
 | 
			
		||||
        font-weight: 500;
 | 
			
		||||
        color: #333;
 | 
			
		||||
        overflow: hidden; 
 | 
			
		||||
        text-overflow:ellipsis; 
 | 
			
		||||
        white-space: nowrap;
 | 
			
		||||
        margin-bottom: 12px;
 | 
			
		||||
        .color-0063E5{
 | 
			
		||||
          color: #0063E5;
 | 
			
		||||
        }
 | 
			
		||||
        .color-FF8100{
 | 
			
		||||
          color: #FF8100;
 | 
			
		||||
        }
 | 
			
		||||
        .color-FF4466{
 | 
			
		||||
          color: #FF4466;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      p{
 | 
			
		||||
        font-family: PingFangSC-Regular, PingFang SC;
 | 
			
		||||
        font-weight: 400;
 | 
			
		||||
        color: #666;
 | 
			
		||||
        line-height: 40px;
 | 
			
		||||
        text-overflow: -o-ellipsis-lastline;
 | 
			
		||||
        overflow: hidden;
 | 
			
		||||
        text-overflow: ellipsis;
 | 
			
		||||
        display: -webkit-box;
 | 
			
		||||
        -webkit-line-clamp: 2;
 | 
			
		||||
        line-clamp: 2;
 | 
			
		||||
        word-break: break-all;
 | 
			
		||||
        -webkit-box-orient: vertical;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  .add-img{
 | 
			
		||||
    width: 120px;
 | 
			
		||||
    position: fixed;
 | 
			
		||||
    bottom: 120px;
 | 
			
		||||
    right: 32px;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										96
									
								
								src/pages/resourcesManage/talking.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,96 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="talking">
 | 
			
		||||
    <div class="header">
 | 
			
		||||
      <p>刘家河村委会、张家村…等<span>20</span>个设备</p>
 | 
			
		||||
      <img src="./img/right-img.png" alt="">
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="content">
 | 
			
		||||
      <!-- <p class="time">00:00:13</p> -->
 | 
			
		||||
      <img src="./img/body.png" alt="">
 | 
			
		||||
      <p class="text">请先选择设备</p>
 | 
			
		||||
      <p class="text">再点击下方按钮开始喊话~</p>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="footer">
 | 
			
		||||
      <img src="./img/stop-img.png" alt="">
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
<script> 
 | 
			
		||||
export default {
 | 
			
		||||
  name: "talking",
 | 
			
		||||
  data() {
 | 
			
		||||
    return {
 | 
			
		||||
      
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    
 | 
			
		||||
  },
 | 
			
		||||
  mounted() {
 | 
			
		||||
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
uni-page-body{
 | 
			
		||||
  background-color: #fff;
 | 
			
		||||
}
 | 
			
		||||
.talking {
 | 
			
		||||
  .header{
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    height: 128px;
 | 
			
		||||
    background: #F6F8FC;
 | 
			
		||||
    padding: 42px 32px;
 | 
			
		||||
    box-sizing: border-box;
 | 
			
		||||
    display: flex;
 | 
			
		||||
    justify-content: space-between;
 | 
			
		||||
    p{
 | 
			
		||||
      font-size: 32px;
 | 
			
		||||
      color: #333;
 | 
			
		||||
      line-height: 44px;
 | 
			
		||||
      span{
 | 
			
		||||
        color: #1174FE;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    img{
 | 
			
		||||
      width: 32px;
 | 
			
		||||
      height: 32px;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  .content{
 | 
			
		||||
    margin-top: 224px;
 | 
			
		||||
    .time{
 | 
			
		||||
      width: 100%;
 | 
			
		||||
      text-align: center;
 | 
			
		||||
      font-size: 96px;
 | 
			
		||||
      color: #000000;
 | 
			
		||||
      line-height: 134px;
 | 
			
		||||
    }
 | 
			
		||||
    img{
 | 
			
		||||
      width: 406px;
 | 
			
		||||
      height: 306px;
 | 
			
		||||
      margin: 0 0 48px 172px;
 | 
			
		||||
    }
 | 
			
		||||
    .text{
 | 
			
		||||
      font-size: 30px;
 | 
			
		||||
      color: #999;
 | 
			
		||||
      line-height: 42px;
 | 
			
		||||
      text-align: center;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  .footer{
 | 
			
		||||
    position: fixed;
 | 
			
		||||
    bottom: 0;
 | 
			
		||||
    left: 0;
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    height: 168px;
 | 
			
		||||
    background: #F6F8FC;
 | 
			
		||||
    padding: 20px 310px;
 | 
			
		||||
    box-sizing: border-box;
 | 
			
		||||
    img{
 | 
			
		||||
      width: 128px;
 | 
			
		||||
      height: 128px;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										69
									
								
								src/pages/snapshot/components/handlePage/handlePage.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,69 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="result-page">
 | 
			
		||||
    <img :src="imgSrc" alt="">
 | 
			
		||||
    <text>{{text}}</text>
 | 
			
		||||
    <u-button type="primary" :custom-style="{width:'100%',borderRadius:'4px',marginTop:'48px'}" @click="goBack">{{btnText}}</u-button>
 | 
			
		||||
    <back></back>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
  import Back from "../../../../components/AiBack"
 | 
			
		||||
  export default {
 | 
			
		||||
    name: "handlePage",
 | 
			
		||||
    components: {Back},
 | 
			
		||||
    data() {
 | 
			
		||||
      return {
 | 
			
		||||
        flag: true
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    onLoad(val) {
 | 
			
		||||
      if (val.flag) {
 | 
			
		||||
        this.flag = val.flag
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    methods: {
 | 
			
		||||
      goBack() {
 | 
			
		||||
        uni.navigateBack({
 | 
			
		||||
          delta:2
 | 
			
		||||
        })
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    computed: {
 | 
			
		||||
      text(){
 | 
			
		||||
        return this.flag ? '处理成功!' : '处理失败'
 | 
			
		||||
      },
 | 
			
		||||
      btnText(){
 | 
			
		||||
        return this.flag ? '查看详情' : '我知道了'
 | 
			
		||||
      },
 | 
			
		||||
      imgSrc(){
 | 
			
		||||
        return this.flag ? (this.imgOtherUrl + 'kztcg.png') : (this.imgOtherUrl + 'kztsb.png')
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
  .result-page {
 | 
			
		||||
    min-height: 100%;
 | 
			
		||||
    background-color: #ffffff;
 | 
			
		||||
    display: flex;
 | 
			
		||||
    flex-direction: column;
 | 
			
		||||
    align-items: center;
 | 
			
		||||
    padding: 96px ;
 | 
			
		||||
 | 
			
		||||
    img {
 | 
			
		||||
      width: 192px;
 | 
			
		||||
      height: 192px;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    text{
 | 
			
		||||
      font-size: 36px;
 | 
			
		||||
      font-weight: 800;
 | 
			
		||||
      color: #333333;
 | 
			
		||||
      line-height: 50px;
 | 
			
		||||
      display: flex;
 | 
			
		||||
      justify-content: center;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										310
									
								
								src/pages/snapshot/handleResult.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,310 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="report-wrapper">
 | 
			
		||||
    <div class="report-form">
 | 
			
		||||
      <div class="form-item">
 | 
			
		||||
        <div class="form-item__left" shrink>
 | 
			
		||||
          <i>*</i>
 | 
			
		||||
          <label>上报类型</label>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="form-item__right">
 | 
			
		||||
          <ai-select :list="reportTypes" @data="selectReportType"/>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div v-if="reportType" class="form-item">
 | 
			
		||||
        <div class="form-item__left" shrink>
 | 
			
		||||
          <i>*</i>
 | 
			
		||||
          <label>事件类型</label>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="form-item__right">
 | 
			
		||||
          <ai-select :list="eventTypes" :value="eventType" @data="selectEventType"/>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
 | 
			
		||||
      <div class="form-item" v-if="!!eventType">
 | 
			
		||||
        <div class="form-item__left">
 | 
			
		||||
          <i>*</i>
 | 
			
		||||
          <label>信用积分</label>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="form-item__right">
 | 
			
		||||
          <span class="score"> {{ integralType }}{{ integralScore }}</span>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
 | 
			
		||||
      <div class="form-area">
 | 
			
		||||
        <div class="form-area__top">
 | 
			
		||||
          <i>*</i>
 | 
			
		||||
          <label>处理结果</label>
 | 
			
		||||
        </div>
 | 
			
		||||
        <textarea
 | 
			
		||||
            placeholder="请输入处理结果描述(200字以内)"
 | 
			
		||||
            :maxlength="200"
 | 
			
		||||
            v-model="explain"
 | 
			
		||||
        ></textarea>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="form-area">
 | 
			
		||||
        <div class="form-area__top">
 | 
			
		||||
          <!--          <i>*</i>-->
 | 
			
		||||
          <label>图片上传(最多9张)</label>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="uploader">
 | 
			
		||||
          <ai-uploader
 | 
			
		||||
              :limit="9"
 | 
			
		||||
              multiple
 | 
			
		||||
              @data="e=>files.push(e.file)"
 | 
			
		||||
              @change="e=>files = e"
 | 
			
		||||
          ></ai-uploader>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div bottom>
 | 
			
		||||
      <u-button type="primary" @click="handleSubmit">提交</u-button>
 | 
			
		||||
    </div>
 | 
			
		||||
    <back></back>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import AiUploader from '../../components/AiUploader'
 | 
			
		||||
import Back from '../../components/AiBack'
 | 
			
		||||
import AiSelect from '../../components/AiSelect'
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: 'handleResult',
 | 
			
		||||
  computed: {
 | 
			
		||||
    eventTypes() {
 | 
			
		||||
      return this.eventTypeList.map(e => ({value: e.id, label: e.ruleName}))
 | 
			
		||||
    },
 | 
			
		||||
    reportTypes() {
 | 
			
		||||
      return this.$dict.getDict('integralDetailType').map(e => ({value: e.dictValue, label: e.dictName}))
 | 
			
		||||
    },
 | 
			
		||||
    integralScore() {
 | 
			
		||||
      return (
 | 
			
		||||
          this.eventTypeList?.find(e => e.id == this.eventType)?.integral || 0
 | 
			
		||||
      )
 | 
			
		||||
    },
 | 
			
		||||
    integralType() {
 | 
			
		||||
      return this.integralScore == 0
 | 
			
		||||
          ? ''
 | 
			
		||||
          : this.eventTypeList?.find(e => e.id == this.eventType)?.integralType ==
 | 
			
		||||
          0
 | 
			
		||||
              ? ''
 | 
			
		||||
              : '+'
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  data() {
 | 
			
		||||
    return {
 | 
			
		||||
      eventType: '',//事件类型
 | 
			
		||||
      reportType: '',//上报类型
 | 
			
		||||
      dictList: [],
 | 
			
		||||
      eventTypeList: [],
 | 
			
		||||
      id: null,
 | 
			
		||||
      reportIndex: null,
 | 
			
		||||
      files: [],
 | 
			
		||||
      explain: ''
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  components: {AiSelect, Back, AiUploader},
 | 
			
		||||
  onLoad(opt) {
 | 
			
		||||
    if (opt) {
 | 
			
		||||
      let {id, reportType} = opt
 | 
			
		||||
      this.id = id
 | 
			
		||||
      this.reportType = reportType
 | 
			
		||||
      this.$dict.load(['integralDetailType']).then(() => {
 | 
			
		||||
        this.getDetailTypes(reportType)
 | 
			
		||||
      })
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    selectEventType(selecteds) {
 | 
			
		||||
      this.eventType = selecteds?.[0]?.value
 | 
			
		||||
    },
 | 
			
		||||
    selectReportType(selecteds) {
 | 
			
		||||
      this.reportType = ""
 | 
			
		||||
      this.$nextTick(() => {
 | 
			
		||||
        this.reportType = selecteds?.[0]?.value
 | 
			
		||||
        this.eventType = ""
 | 
			
		||||
        this.getDetailTypes(this.reportType)
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
    getDetailTypes(classification) {
 | 
			
		||||
      this.$http.post(`/app/appvillagerintegralrule/listForWx`, null, {
 | 
			
		||||
        params: {classification, current: 1, size: 999, ruleStatus: 1}
 | 
			
		||||
      }).then(res => {
 | 
			
		||||
        if (res?.data) {
 | 
			
		||||
          this.eventTypeList = res.data.records
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
    handleSubmit() {
 | 
			
		||||
      if (!this.reportType) {
 | 
			
		||||
        return this.$u.toast("请选择上报类型")
 | 
			
		||||
      }
 | 
			
		||||
      if (!this.eventType) {
 | 
			
		||||
        return this.$u.toast("请选择事件类型")
 | 
			
		||||
      }
 | 
			
		||||
      if (this.explain == '') {
 | 
			
		||||
        return this.$u.toast("请填写处理结果")
 | 
			
		||||
      }
 | 
			
		||||
      this.$http.post(`/app/appreportatwillinfo/handle`, {
 | 
			
		||||
        handleFiles: this.files,
 | 
			
		||||
        reportType: this.reportType,
 | 
			
		||||
        ruleId: this.eventType,
 | 
			
		||||
        handleResult: this.explain,
 | 
			
		||||
        id: this.id
 | 
			
		||||
      })
 | 
			
		||||
      .then(res => {
 | 
			
		||||
        if (res?.code == 0) {
 | 
			
		||||
          uni.navigateTo({
 | 
			
		||||
            url: '/pages/snapshot/components/handlePage/handlePage'
 | 
			
		||||
          })
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
      .catch(e => {
 | 
			
		||||
        this.$u.toast(e || '网络异常')
 | 
			
		||||
      })
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
.report-wrapper {
 | 
			
		||||
  min-height: 100%;
 | 
			
		||||
  padding-bottom: 112px;
 | 
			
		||||
  box-sizing: border-box;
 | 
			
		||||
  background-color: #f3f6f9;
 | 
			
		||||
 | 
			
		||||
  .report-btn {
 | 
			
		||||
    position: fixed;
 | 
			
		||||
    bottom: 0;
 | 
			
		||||
    left: 0;
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    height: 112px;
 | 
			
		||||
    line-height: 112px;
 | 
			
		||||
    text-align: center;
 | 
			
		||||
    color: #ffffff;
 | 
			
		||||
    font-size: 34px;
 | 
			
		||||
    font-weight: 600;
 | 
			
		||||
    background: #135ab8;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.phone {
 | 
			
		||||
  text-align: right;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.address {
 | 
			
		||||
  max-width: 400px;
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
  text-overflow: ellipsis;
 | 
			
		||||
  white-space: nowrap;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
::v-deep .picker {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  height: 112px;
 | 
			
		||||
  line-height: 112px;
 | 
			
		||||
  font-size: 32px;
 | 
			
		||||
 | 
			
		||||
  span {
 | 
			
		||||
    position: relative;
 | 
			
		||||
    top: -10px;
 | 
			
		||||
    font-size: 32px;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
::v-deep .picker .AiArea {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  height: 112px;
 | 
			
		||||
  line-height: 112px;
 | 
			
		||||
  background-color: #fff !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.form-area {
 | 
			
		||||
  margin-bottom: 16px;
 | 
			
		||||
  padding: 34px 32px 34px 32px;
 | 
			
		||||
  background: #fff;
 | 
			
		||||
 | 
			
		||||
  .form-area__top {
 | 
			
		||||
    display: flex;
 | 
			
		||||
    align-items: center;
 | 
			
		||||
    margin-bottom: 32px;
 | 
			
		||||
 | 
			
		||||
    i {
 | 
			
		||||
      margin-right: 4px;
 | 
			
		||||
      color: #ff4466;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    label {
 | 
			
		||||
      color: #333333 !important;
 | 
			
		||||
      font-size: 32px;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  textarea {
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    height: 140px;
 | 
			
		||||
    padding-left: 16px;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .uploader {
 | 
			
		||||
    padding-left: 16px;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.form-item {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  justify-content: space-between;
 | 
			
		||||
  height: 112px;
 | 
			
		||||
  margin-bottom: 16px;
 | 
			
		||||
  padding: 0 32px 0 32px;
 | 
			
		||||
  background: #fff;
 | 
			
		||||
 | 
			
		||||
  .form-item__left {
 | 
			
		||||
    display: flex;
 | 
			
		||||
    align-items: center;
 | 
			
		||||
 | 
			
		||||
    i {
 | 
			
		||||
      margin-right: 4px;
 | 
			
		||||
      color: #ff4466;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    label {
 | 
			
		||||
      color: #333333 !important;
 | 
			
		||||
      font-size: 32px;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .form-item__right {
 | 
			
		||||
    flex: 1;
 | 
			
		||||
    min-width: 0;
 | 
			
		||||
    display: flex;
 | 
			
		||||
    align-items: center;
 | 
			
		||||
    justify-content: flex-end;
 | 
			
		||||
    margin-left: 16px;
 | 
			
		||||
 | 
			
		||||
    span {
 | 
			
		||||
      color: #999999;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .score {
 | 
			
		||||
      font-size: 34px;
 | 
			
		||||
      font-weight: 600;
 | 
			
		||||
      color: #e6736e;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ::v-deep .AiSelect {
 | 
			
		||||
    .display {
 | 
			
		||||
      justify-content: flex-end;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .selectedLabel {
 | 
			
		||||
      text-align: right;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										281
									
								
								src/pages/snapshot/snapshot.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,281 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="snapshot">
 | 
			
		||||
    <div class="banner">
 | 
			
		||||
      <picker :range="dictList" @change="bindPickerChange" range-key="dictName">
 | 
			
		||||
        <div class="picker">
 | 
			
		||||
          {{ reportType }}
 | 
			
		||||
          <u-icon
 | 
			
		||||
              name="arrow-down"
 | 
			
		||||
              :custom-style="{ margin: '0 4px' }"
 | 
			
		||||
          ></u-icon>
 | 
			
		||||
        </div>
 | 
			
		||||
      </picker>
 | 
			
		||||
      <u-search
 | 
			
		||||
          placeholder="请输入标题"
 | 
			
		||||
          :show-action="false"
 | 
			
		||||
          v-model="keyword"
 | 
			
		||||
          @clear="search"
 | 
			
		||||
          @search="search"
 | 
			
		||||
      />
 | 
			
		||||
    </div>
 | 
			
		||||
    <u-tabs
 | 
			
		||||
        class="nav"
 | 
			
		||||
        :list="tabs"
 | 
			
		||||
        :is-scroll="false"
 | 
			
		||||
        :current="currentType"
 | 
			
		||||
        font-size="32"
 | 
			
		||||
        bar-width="192"
 | 
			
		||||
        height="96"
 | 
			
		||||
        @change="handleTabClick"
 | 
			
		||||
    />
 | 
			
		||||
    <div class="body" v-if="eventList.length > 0">
 | 
			
		||||
      <div
 | 
			
		||||
          class="item"
 | 
			
		||||
          v-for="(item, index) in eventList"
 | 
			
		||||
          :key="index"
 | 
			
		||||
          @click="detail(item)"
 | 
			
		||||
      >
 | 
			
		||||
        <u-row justify="between">
 | 
			
		||||
          <u-row>
 | 
			
		||||
            <img
 | 
			
		||||
              class="avatar"
 | 
			
		||||
              :src="item.portrait ? item.portrait : imgOtherUrl + 'tx.png'"
 | 
			
		||||
              alt=""/>
 | 
			
		||||
            <div class="wrap">
 | 
			
		||||
              <span class="name">{{ item.nickName }}</span>
 | 
			
		||||
              <span class="date">{{ item.createTime }}</span>
 | 
			
		||||
            </div>
 | 
			
		||||
          </u-row>
 | 
			
		||||
          <u-row>
 | 
			
		||||
            <u-icon :name="$cdn + 'Location2@2x.png'" :custom-style="{width:'20px',height:'20px'}"></u-icon>
 | 
			
		||||
            <span class="date">{{item.areaName}}</span>
 | 
			
		||||
          </u-row>
 | 
			
		||||
        </u-row>
 | 
			
		||||
        <div class="content">
 | 
			
		||||
          <span class="text">
 | 
			
		||||
            <span class="targ" v-if="item.reportType">{{
 | 
			
		||||
                $dict.getLabel('atWillReportTypeForCp', item.reportType)
 | 
			
		||||
              }}</span>
 | 
			
		||||
            {{ item.explain }}</span>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="photos">
 | 
			
		||||
          <img
 | 
			
		||||
              :src="photo.url"
 | 
			
		||||
              v-for="(photo, idx) in item.files.slice(0,3)"
 | 
			
		||||
              :key="idx"
 | 
			
		||||
              @click.stop="previewImage(index, idx)"
 | 
			
		||||
          />
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <AiEmpty v-else/>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import AiEmpty from '../../components/AiEmpty/AiEmpty'
 | 
			
		||||
import {mapState} from "vuex"
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: "snapshot",
 | 
			
		||||
  components: {AiEmpty},
 | 
			
		||||
  data() {
 | 
			
		||||
    return {
 | 
			
		||||
      dictList: [],
 | 
			
		||||
      index: 0,
 | 
			
		||||
      keyword: '',
 | 
			
		||||
      currentCategory: '',
 | 
			
		||||
      currentType: 0,
 | 
			
		||||
      reportType: '上报类型',
 | 
			
		||||
      reportIndex: '',
 | 
			
		||||
      pageNum: 1,
 | 
			
		||||
      pages: 2,
 | 
			
		||||
      eventList: [],
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  onShow() {
 | 
			
		||||
    this.$dict.load('atWillReportTypeForCp').then(() => {
 | 
			
		||||
      this.dictList = this.$dict.getDict('atWillReportTypeForCp')
 | 
			
		||||
      this.getList()
 | 
			
		||||
    })
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  methods: {
 | 
			
		||||
    detail(item) {
 | 
			
		||||
      uni.navigateTo({
 | 
			
		||||
        url: "/pages/snapshot/snapshotDetail?id=" + item.id
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
    bindPickerChange(e) {
 | 
			
		||||
      this.pageNum = 1;
 | 
			
		||||
      this.pages = 2;
 | 
			
		||||
      let index = e.detail.value
 | 
			
		||||
      this.reportType = this.dictList[index].dictName
 | 
			
		||||
      this.reportIndex = index
 | 
			
		||||
      this.getList()
 | 
			
		||||
    },
 | 
			
		||||
    handleTabClick(i) {
 | 
			
		||||
      this.currentType = i
 | 
			
		||||
      this.pageNum = 1;
 | 
			
		||||
      this.pages = 2;
 | 
			
		||||
      this.getList()
 | 
			
		||||
    },
 | 
			
		||||
    search() {
 | 
			
		||||
      this.pageNum = 1;
 | 
			
		||||
      this.pages = 2;
 | 
			
		||||
      this.getList()
 | 
			
		||||
    },
 | 
			
		||||
    previewImage(index, idx) {
 | 
			
		||||
      uni.previewImage({
 | 
			
		||||
        urls: this.eventList[index]['files'].map(e => e.url),
 | 
			
		||||
        current: this.eventList[index]['files'][idx].url
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
    getList() {
 | 
			
		||||
      if (this.pageNum > this.pages) return
 | 
			
		||||
      this.$http.post(`/app/appreportatwillinfo/list`, null, {
 | 
			
		||||
        params: {
 | 
			
		||||
          current: this.pageNum,
 | 
			
		||||
          size: 10,
 | 
			
		||||
          status: this.currentType,
 | 
			
		||||
          reportType: this.reportIndex == 6 ? null : this.reportIndex,
 | 
			
		||||
          address: this.keyword,
 | 
			
		||||
          areaId:this.user?.areaId
 | 
			
		||||
        }
 | 
			
		||||
      }).then(res => {
 | 
			
		||||
        if (res?.code == 0) {
 | 
			
		||||
          const eventList = this.pageNum > 1 ? [...this.eventList, ...res.data.records] : res.data.records
 | 
			
		||||
          this.pages = Math.ceil(res.data.total / 10)
 | 
			
		||||
          this.eventList = eventList
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  onReachBottom() {
 | 
			
		||||
    this.pageNum = this.pageNum + 1
 | 
			
		||||
    this.getList()
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  computed: {
 | 
			
		||||
    ...mapState(["user"]),
 | 
			
		||||
    tabs() {
 | 
			
		||||
      return [
 | 
			
		||||
        {name: "待处理", value: 0},
 | 
			
		||||
        {name: "处理完成", value: 1},
 | 
			
		||||
      ]
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
.snapshot {
 | 
			
		||||
  min-height: 100%;
 | 
			
		||||
  background: #F5F5F5;
 | 
			
		||||
 | 
			
		||||
  .banner {
 | 
			
		||||
    background-color: #ffffff;
 | 
			
		||||
    height: 80px;
 | 
			
		||||
    display: flex;
 | 
			
		||||
    align-items: center;
 | 
			
		||||
    justify-content: space-between;
 | 
			
		||||
    box-sizing: border-box;
 | 
			
		||||
    padding: 0 30px;
 | 
			
		||||
 | 
			
		||||
    .picker {
 | 
			
		||||
      font-size: 30px;
 | 
			
		||||
      font-weight: 500;
 | 
			
		||||
      color: #333333;
 | 
			
		||||
      margin-right: 8px;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .nav {
 | 
			
		||||
    background-color: #ffffff;
 | 
			
		||||
    height: 96px;
 | 
			
		||||
    padding-top: 8px;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .body {
 | 
			
		||||
    .item {
 | 
			
		||||
      background-color: #ffffff;
 | 
			
		||||
      box-sizing: border-box;
 | 
			
		||||
      padding: 30px;
 | 
			
		||||
      margin-top: 16px;
 | 
			
		||||
 | 
			
		||||
      .avatar {
 | 
			
		||||
        width: 64px;
 | 
			
		||||
        height: 64px;
 | 
			
		||||
        border-radius: 50%;
 | 
			
		||||
        margin-right: 8px;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .wrap {
 | 
			
		||||
        display: flex;
 | 
			
		||||
        flex-direction: column;
 | 
			
		||||
        justify-content: center;
 | 
			
		||||
 | 
			
		||||
        .name {
 | 
			
		||||
          font-size: 26px;
 | 
			
		||||
          font-weight: 500;
 | 
			
		||||
          color: #333333;
 | 
			
		||||
          line-height: 24px;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .date {
 | 
			
		||||
        font-size: 22px;
 | 
			
		||||
        color: #999999;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .content {
 | 
			
		||||
        padding: 18px 0;
 | 
			
		||||
        display: flex;
 | 
			
		||||
        flex-wrap: wrap;
 | 
			
		||||
 | 
			
		||||
        .text {
 | 
			
		||||
          font-size: 26px;
 | 
			
		||||
          font-weight: 400;
 | 
			
		||||
          color: #333333;
 | 
			
		||||
          line-height: 44px;
 | 
			
		||||
          overflow: hidden;
 | 
			
		||||
          display: -webkit-box;
 | 
			
		||||
          text-overflow: ellipsis;
 | 
			
		||||
          -webkit-box-orient: vertical;
 | 
			
		||||
          -webkit-line-clamp: 3;
 | 
			
		||||
 | 
			
		||||
          .targ {
 | 
			
		||||
            padding: 6px;
 | 
			
		||||
            background: #E8EFFF;
 | 
			
		||||
            border-radius: 8px;
 | 
			
		||||
            font-size: 24px;
 | 
			
		||||
            font-weight: 400;
 | 
			
		||||
            color: #2266FF;
 | 
			
		||||
            margin-right: 8px;
 | 
			
		||||
            line-height: 34px;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .photos {
 | 
			
		||||
        display: flex;
 | 
			
		||||
        flex-wrap: wrap;
 | 
			
		||||
 | 
			
		||||
        & > img {
 | 
			
		||||
          width: 224px;
 | 
			
		||||
          height: 224px;
 | 
			
		||||
          margin: 0 8px 8px 0;
 | 
			
		||||
 | 
			
		||||
          &:nth-child(3n) {
 | 
			
		||||
            margin-right: 0;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										226
									
								
								src/pages/snapshot/snapshotDetail.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,226 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="snapshot-detail">
 | 
			
		||||
    <div class="info">
 | 
			
		||||
      <div class="info-item">
 | 
			
		||||
        <text>上报人:</text>
 | 
			
		||||
        <text>{{ detail.nickName }}</text>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="info-item">
 | 
			
		||||
        <text>联系电话:</text>
 | 
			
		||||
        <text>{{ detail.phone }}</text>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="info-item">
 | 
			
		||||
        <text>上报时间:</text>
 | 
			
		||||
        <text>{{ detail.createTime }}</text>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="info-item">
 | 
			
		||||
        <text>处理状态:</text>
 | 
			
		||||
        <text>{{ $dict.getLabel('reportAtWillHandleStatus', detail.status) }}</text>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="body">
 | 
			
		||||
      <u-row class="location" justify="space-between">
 | 
			
		||||
        <text>{{ detail.address }}</text>
 | 
			
		||||
        <u-icon :name="$cdn + 'Location2@2x.png'" :custom-style="{width:'24px',height:'24px'}"></u-icon>
 | 
			
		||||
      </u-row>
 | 
			
		||||
      <u-row justify="space-between" class="type" v-if="detail.reportType">
 | 
			
		||||
        <text>上报类型</text>
 | 
			
		||||
        <text>{{ $dict.getLabel('integralDetailType', detail.reportType) }}</text>
 | 
			
		||||
      </u-row>
 | 
			
		||||
      <text class="title">事件描述</text>
 | 
			
		||||
      <div class="content">{{ detail.explain }}</div>
 | 
			
		||||
      <div class="photos">
 | 
			
		||||
        <img :src="item.url" alt="" v-for="(item,index) in detail.files" :key="index" @click.stop="previewImage(detail.files,index)">
 | 
			
		||||
      </div>
 | 
			
		||||
      <template v-if="detail.handleResult">
 | 
			
		||||
        <u-row justify="space-between" class="result">
 | 
			
		||||
          <text class="title">处理结果</text>
 | 
			
		||||
          <text>{{detail.integral|formt}}</text>
 | 
			
		||||
        </u-row>
 | 
			
		||||
        <div class="content">{{ detail.handleResult }}</div>
 | 
			
		||||
        <div class="photos">
 | 
			
		||||
          <img :src="item.url" alt="" v-for="(item,index) in detail.handleFiles" :key="index"
 | 
			
		||||
               @click.stop="previewImage(detail.handleFiles,index)">
 | 
			
		||||
        </div>
 | 
			
		||||
        <u-row justify="space-between" class="type">
 | 
			
		||||
          <div shrink>事件类型</div>
 | 
			
		||||
          <text>{{ detail.ruleName }}</text>
 | 
			
		||||
        </u-row>
 | 
			
		||||
        <u-row justify="space-between" class="type">
 | 
			
		||||
          <text>处理人</text>
 | 
			
		||||
          <text class="nonmal">{{ detail.handleUserName }}</text>
 | 
			
		||||
        </u-row>
 | 
			
		||||
        <!--        <u-row justify="space-between" class="type">-->
 | 
			
		||||
        <!--          <text>联系电话</text>-->
 | 
			
		||||
        <!--          <text class="nonmal">18707170017</text>-->
 | 
			
		||||
        <!--        </u-row>-->
 | 
			
		||||
        <u-row justify="space-between" class="type">
 | 
			
		||||
          <text>处理时间</text>
 | 
			
		||||
          <text class="nonmal">{{ detail.handleTime }}</text>
 | 
			
		||||
        </u-row>
 | 
			
		||||
      </template>
 | 
			
		||||
 | 
			
		||||
    </div>
 | 
			
		||||
    <div bottom v-if="!detail.handleResult">
 | 
			
		||||
      <u-button type="primary" v-if="!detail.handleResult" @click="handle">去处理</u-button>
 | 
			
		||||
    </div>
 | 
			
		||||
    <back></back>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import Back from "../../components/AiBack";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: "snapshotDetail",
 | 
			
		||||
  components: {Back},
 | 
			
		||||
  onLoad(opt) {
 | 
			
		||||
    if (opt.id) {
 | 
			
		||||
      this.id = opt.id
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  onShow() {
 | 
			
		||||
    this.$dict.load('reportAtWillHandleStatus', 'integralDetailType').then(() => {
 | 
			
		||||
      this.getDetail()
 | 
			
		||||
    })
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  data() {
 | 
			
		||||
    return {
 | 
			
		||||
      detail: {},
 | 
			
		||||
      id: null,
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    previewImage(data,index) {
 | 
			
		||||
      uni.previewImage({
 | 
			
		||||
        urls: data.map(e => e.url),
 | 
			
		||||
        current: data[index].url
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
    handle() {
 | 
			
		||||
      uni.navigateTo({
 | 
			
		||||
        url: `/pages/snapshot/handleResult?id=${this.id}&reportType=${this.detail.reportType}`
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
    getDetail() {
 | 
			
		||||
      this.$http.post(`/app/appreportatwillinfo/queryDetailById`, null, {
 | 
			
		||||
        params: {
 | 
			
		||||
          id: this.id
 | 
			
		||||
        }
 | 
			
		||||
      }).then(res => {
 | 
			
		||||
        if (res.code == 0) {
 | 
			
		||||
          this.detail = res.data
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  filters:{
 | 
			
		||||
    formt(val){
 | 
			
		||||
      return +val > 0 ? `+${val}` : val
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
.snapshot-detail {
 | 
			
		||||
  min-height: 100%;
 | 
			
		||||
  background-color: #F3F6F9;
 | 
			
		||||
  padding-bottom: 160px;
 | 
			
		||||
 | 
			
		||||
  .info {
 | 
			
		||||
    height: 384px;
 | 
			
		||||
    background-color: #3975C6;
 | 
			
		||||
    box-sizing: border-box;
 | 
			
		||||
    padding: 32px;
 | 
			
		||||
 | 
			
		||||
    .info-item {
 | 
			
		||||
      font-size: 28px;
 | 
			
		||||
      font-weight: 400;
 | 
			
		||||
      color: #FFFFFF;
 | 
			
		||||
      line-height: 40px;
 | 
			
		||||
      margin-bottom: 16px;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .body {
 | 
			
		||||
    width: 686px;
 | 
			
		||||
    margin: 0 auto;
 | 
			
		||||
    margin-top: -96px;
 | 
			
		||||
    background: #FFFFFF;
 | 
			
		||||
    box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.02);
 | 
			
		||||
    border-radius: 8px;
 | 
			
		||||
    box-sizing: border-box;
 | 
			
		||||
    padding: 34px 32px;
 | 
			
		||||
 | 
			
		||||
    .location {
 | 
			
		||||
      & > text {
 | 
			
		||||
        font-size: 32px;
 | 
			
		||||
        font-weight: 800;
 | 
			
		||||
        color: #333333;
 | 
			
		||||
        line-height: 44px;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .type {
 | 
			
		||||
      font-size: 32px;
 | 
			
		||||
      margin: 68px 0;
 | 
			
		||||
 | 
			
		||||
      & > text:nth-child(1) {
 | 
			
		||||
        color: #666666;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      & > text:nth-child(2) {
 | 
			
		||||
        color: #135AB8;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .nonmal {
 | 
			
		||||
        color: #333333 !important;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .title {
 | 
			
		||||
      font-size: 32px;
 | 
			
		||||
      color: #666666;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .content {
 | 
			
		||||
      margin-top: 10px;
 | 
			
		||||
      font-size: 32px;
 | 
			
		||||
      color: #333333;
 | 
			
		||||
      line-height: 44px;
 | 
			
		||||
      word-break: break-all;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .photos {
 | 
			
		||||
      display: flex;
 | 
			
		||||
      flex-wrap: wrap;
 | 
			
		||||
      margin: 30px 0;
 | 
			
		||||
 | 
			
		||||
      & > img {
 | 
			
		||||
        width: 196px;
 | 
			
		||||
        height: 196px;
 | 
			
		||||
        margin: 0 14px 14px 0;
 | 
			
		||||
        flex-shrink: 0;
 | 
			
		||||
 | 
			
		||||
        &:nth-child(3n) {
 | 
			
		||||
          margin-right: 0;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .result {
 | 
			
		||||
      margin-top: 48px;
 | 
			
		||||
 | 
			
		||||
      & > text:nth-child(2) {
 | 
			
		||||
        font-size: 34px;
 | 
			
		||||
        font-weight: 600;
 | 
			
		||||
        color: #E6736E;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										286
									
								
								src/pages/supermarket/balance.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,286 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="balance">
 | 
			
		||||
    <div class="operate">
 | 
			
		||||
      <div class="target">结算对象</div>
 | 
			
		||||
      <div class="select" @click="handleSelect">
 | 
			
		||||
        {{
 | 
			
		||||
          selected
 | 
			
		||||
            ? `${selected.familyName}家 剩余积分:${selected.familyIntegral}分`
 | 
			
		||||
            : '请选择'
 | 
			
		||||
        }}
 | 
			
		||||
        <u-icon name="arrow-right" color="#E2E2E2" size="28"></u-icon>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div class="line" :style="{ backgroundImage: 'url(' + uri + ')' }"></div>
 | 
			
		||||
 | 
			
		||||
    <scroll-view scroll-y class="category-wrap">
 | 
			
		||||
      <div
 | 
			
		||||
        class="category-item"
 | 
			
		||||
        v-for="(item, index) in categoryList"
 | 
			
		||||
        :key="index"
 | 
			
		||||
      >
 | 
			
		||||
        <img class="category-img" :src="parseObj(item.photo)" alt="" />
 | 
			
		||||
        <div class="category-info">
 | 
			
		||||
          <label class="hidden">{{ item.merchandiseName }}</label>
 | 
			
		||||
          <span class="score"
 | 
			
		||||
            >{{ item.costIntegral }}
 | 
			
		||||
            <span>积分</span>
 | 
			
		||||
          </span>
 | 
			
		||||
          <div class="wrap">×{{ item.merchandiseNumber }}</div>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </scroll-view>
 | 
			
		||||
    <div class="footer">
 | 
			
		||||
      <div class="sum">
 | 
			
		||||
        <span>共{{ totalCount }}件商品</span>
 | 
			
		||||
        <span
 | 
			
		||||
          >合计:{{ totalScore }}
 | 
			
		||||
          <span>积分</span>
 | 
			
		||||
        </span>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="btn" @click="hanldeSubmit">确认领取</div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <back />
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import Back from '../../components/AiBack'
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: 'balance',
 | 
			
		||||
  components: { Back },
 | 
			
		||||
  data() {
 | 
			
		||||
    return {
 | 
			
		||||
      selected: null,
 | 
			
		||||
      categoryList: [],
 | 
			
		||||
      totalScore: 0,
 | 
			
		||||
      totalCount: 0
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  onLoad(opt) {
 | 
			
		||||
    if (opt.category) {
 | 
			
		||||
      let sum = 0
 | 
			
		||||
      let count = 0
 | 
			
		||||
      this.categoryList = JSON.parse(opt.category)
 | 
			
		||||
      this.categoryList.map(e => {
 | 
			
		||||
        count += e.merchandiseNumber
 | 
			
		||||
        if (e.merchandiseNumber != 0) {
 | 
			
		||||
          sum += e.merchandiseNumber * e.costIntegral
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
      this.totalScore = sum
 | 
			
		||||
      this.totalCount = count
 | 
			
		||||
    }
 | 
			
		||||
    uni.$on('selected', data => {
 | 
			
		||||
      if (data) {
 | 
			
		||||
        this.selected = data
 | 
			
		||||
      }
 | 
			
		||||
    })
 | 
			
		||||
  },
 | 
			
		||||
  computed: {
 | 
			
		||||
    uri() {
 | 
			
		||||
      return this.imgOtherUrl + 'line.png'
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  methods: {
 | 
			
		||||
    parseObj(json) {
 | 
			
		||||
      return JSON.parse(json || '[]')[0]?.url
 | 
			
		||||
    },
 | 
			
		||||
    hanldeSubmit() {
 | 
			
		||||
      if (!this.selected)
 | 
			
		||||
        return uni.showToast({
 | 
			
		||||
          title: '请选择结算对象',
 | 
			
		||||
          icon: 'none'
 | 
			
		||||
        })
 | 
			
		||||
      let { memberId, familyId } = this.selected
 | 
			
		||||
      this.$http
 | 
			
		||||
        .post(`/app/appvillagerintegralshoporder/addOrder`, {
 | 
			
		||||
          shopId: this.categoryList[0].shopId,
 | 
			
		||||
          memberId,
 | 
			
		||||
          familyId,
 | 
			
		||||
          orderIntegral: this.totalScore,
 | 
			
		||||
          merchandiseList: this.categoryList.map(e => {
 | 
			
		||||
            return {
 | 
			
		||||
              ...e,
 | 
			
		||||
              merchandiseId: e.id
 | 
			
		||||
            }
 | 
			
		||||
          })
 | 
			
		||||
        })
 | 
			
		||||
        .then(res => {
 | 
			
		||||
          if (res.code == 0) {
 | 
			
		||||
            uni.navigateTo({
 | 
			
		||||
              url: '/pages/supermarket/components/resultPage/resultPage'
 | 
			
		||||
            })
 | 
			
		||||
          } else {
 | 
			
		||||
            uni.navigateTo({
 | 
			
		||||
              url:
 | 
			
		||||
                '/pages/supermarket/components/resultPage/resultPage?flag=' +
 | 
			
		||||
                false
 | 
			
		||||
            })
 | 
			
		||||
          }
 | 
			
		||||
        })
 | 
			
		||||
        .catch(e => {
 | 
			
		||||
          uni.showToast({
 | 
			
		||||
            title: e || '网络异常',
 | 
			
		||||
            icon: 'none'
 | 
			
		||||
          })
 | 
			
		||||
        })
 | 
			
		||||
    },
 | 
			
		||||
    handleSelect() {
 | 
			
		||||
      uni.navigateTo({
 | 
			
		||||
        url: '/pages/supermarket/search'
 | 
			
		||||
      })
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
.balance {
 | 
			
		||||
  min-height: 100%;
 | 
			
		||||
  background-color: #ffffff;
 | 
			
		||||
  .operate {
 | 
			
		||||
    height: 120px;
 | 
			
		||||
    display: flex;
 | 
			
		||||
    align-items: center;
 | 
			
		||||
    justify-content: space-between;
 | 
			
		||||
    box-sizing: border-box;
 | 
			
		||||
    padding: 0 30px;
 | 
			
		||||
 | 
			
		||||
    .target {
 | 
			
		||||
      font-size: 32px;
 | 
			
		||||
      color: #333333;
 | 
			
		||||
 | 
			
		||||
      &:before {
 | 
			
		||||
        content: '*';
 | 
			
		||||
        font-size: 32px;
 | 
			
		||||
        color: #ff4466;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .select {
 | 
			
		||||
      font-size: 32px;
 | 
			
		||||
      color: #666666;
 | 
			
		||||
 | 
			
		||||
      & > i {
 | 
			
		||||
        font-size: 20px;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .line {
 | 
			
		||||
    // margin: 0 30px;
 | 
			
		||||
    padding: 0 15px;
 | 
			
		||||
    height: 8px;
 | 
			
		||||
    background-repeat: no-repeat;
 | 
			
		||||
    background-size: cover;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .category-wrap {
 | 
			
		||||
    padding: 16px 0 110px;
 | 
			
		||||
 | 
			
		||||
    .category-item {
 | 
			
		||||
      box-sizing: border-box;
 | 
			
		||||
      padding: 28px 32px 44px 30px;
 | 
			
		||||
      height: 264px;
 | 
			
		||||
      display: flex;
 | 
			
		||||
 | 
			
		||||
      .category-img {
 | 
			
		||||
        width: 192px;
 | 
			
		||||
        height: 192px;
 | 
			
		||||
        border: 1px solid #f6f6f6;
 | 
			
		||||
        flex-shrink: 0;
 | 
			
		||||
        margin-right: 30px;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .category-info {
 | 
			
		||||
        width: 100%;
 | 
			
		||||
        display: flex;
 | 
			
		||||
        flex-direction: column;
 | 
			
		||||
        justify-content: space-between;
 | 
			
		||||
 | 
			
		||||
        & > label {
 | 
			
		||||
          font-size: 30px;
 | 
			
		||||
          font-weight: 800;
 | 
			
		||||
          color: #333333;
 | 
			
		||||
          line-height: 42px;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .score {
 | 
			
		||||
          font-size: 40px;
 | 
			
		||||
          font-weight: 600;
 | 
			
		||||
          color: #fa4a51;
 | 
			
		||||
 | 
			
		||||
          & > span {
 | 
			
		||||
            font-size: 24px;
 | 
			
		||||
            color: #fa4a51;
 | 
			
		||||
            margin-left: 8px;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .wrap {
 | 
			
		||||
          display: flex;
 | 
			
		||||
          justify-content: flex-end;
 | 
			
		||||
          font-weight: 600;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .footer {
 | 
			
		||||
    display: flex;
 | 
			
		||||
    align-items: center;
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    background-color: #ffffff;
 | 
			
		||||
    z-index: 100;
 | 
			
		||||
    height: 104px;
 | 
			
		||||
    box-shadow: 0px -2px 8px 0px rgba(214, 214, 214, 0.5);
 | 
			
		||||
    position: fixed;
 | 
			
		||||
    left: 0;
 | 
			
		||||
    bottom: 0;
 | 
			
		||||
 | 
			
		||||
    .sum {
 | 
			
		||||
      width: calc(100% - 212px);
 | 
			
		||||
      box-sizing: border-box;
 | 
			
		||||
      padding: 30px;
 | 
			
		||||
      display: flex;
 | 
			
		||||
      justify-content: space-between;
 | 
			
		||||
 | 
			
		||||
      & > span:nth-child(1),
 | 
			
		||||
      span:nth-child(2) {
 | 
			
		||||
        font-size: 32px;
 | 
			
		||||
        font-weight: 400;
 | 
			
		||||
        color: #f94246;
 | 
			
		||||
 | 
			
		||||
        & > span {
 | 
			
		||||
          font-size: 24px;
 | 
			
		||||
          margin-left: 12px;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .btn {
 | 
			
		||||
      width: 212px;
 | 
			
		||||
      height: 100%;
 | 
			
		||||
      background-color: #1365dd;
 | 
			
		||||
      font-size: 36px;
 | 
			
		||||
      font-weight: 500;
 | 
			
		||||
      color: #ffffff;
 | 
			
		||||
      display: flex;
 | 
			
		||||
      align-items: center;
 | 
			
		||||
      justify-content: center;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .hidden {
 | 
			
		||||
    overflow: hidden;
 | 
			
		||||
    text-overflow: ellipsis;
 | 
			
		||||
    display: -webkit-box;
 | 
			
		||||
    -webkit-box-orient: vertical;
 | 
			
		||||
    -webkit-line-clamp: 2;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										69
									
								
								src/pages/supermarket/components/resultPage/resultPage.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,69 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="result-page">
 | 
			
		||||
    <img :src="imgSrc" alt="">
 | 
			
		||||
    <text>{{text}}</text>
 | 
			
		||||
    <u-button type="primary" :custom-style="{width:'100%',borderRadius:'4px',marginTop:'48px'}" @click="goBack">{{btnText}}</u-button>
 | 
			
		||||
    <back></back>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
  import Back from "../../../../components/AiBack";
 | 
			
		||||
  export default {
 | 
			
		||||
    name: "result-page",
 | 
			
		||||
    components: {Back},
 | 
			
		||||
    data() {
 | 
			
		||||
      return {
 | 
			
		||||
        flag: true
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    onLoad(val) {
 | 
			
		||||
      if (val.flag) {
 | 
			
		||||
        this.flag = val.flag
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    methods: {
 | 
			
		||||
      goBack() {
 | 
			
		||||
        uni.navigateBack({
 | 
			
		||||
          delta:3
 | 
			
		||||
        })
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    computed: {
 | 
			
		||||
      text(){
 | 
			
		||||
        return this.flag ? '领取成功!' : '领取失败!请联系管理员处理'
 | 
			
		||||
      },
 | 
			
		||||
      btnText(){
 | 
			
		||||
        return this.flag ? '确定' : '我知道了'
 | 
			
		||||
      },
 | 
			
		||||
      imgSrc(){
 | 
			
		||||
        return this.flag ? (this.imgOtherUrl + 'kztcg.png') : (this.imgOtherUrl + 'kztsb.png')
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
  .result-page {
 | 
			
		||||
    min-height: 100%;
 | 
			
		||||
    background-color: #ffffff;
 | 
			
		||||
    display: flex;
 | 
			
		||||
    flex-direction: column;
 | 
			
		||||
    align-items: center;
 | 
			
		||||
    padding: 96px ;
 | 
			
		||||
 | 
			
		||||
    img {
 | 
			
		||||
      width: 192px;
 | 
			
		||||
      height: 192px;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    text{
 | 
			
		||||
      font-size: 36px;
 | 
			
		||||
      font-weight: 800;
 | 
			
		||||
      color: #333333;
 | 
			
		||||
      line-height: 50px;
 | 
			
		||||
      display: flex;
 | 
			
		||||
      justify-content: center;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										120
									
								
								src/pages/supermarket/search.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,120 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="search">
 | 
			
		||||
    <div class="search-wrap">
 | 
			
		||||
      <u-search :show-action="false" placeholder="请输入手机号或身份证号搜索" v-model.trim="keyword" @search="search"></u-search>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="result-body">
 | 
			
		||||
      <div class="res-item" v-if="result" @click="selected">
 | 
			
		||||
        <span>{{result.familyName}}家</span>
 | 
			
		||||
        <span>剩余积分:{{result.familyIntegral}}分</span>
 | 
			
		||||
      </div>
 | 
			
		||||
      <span class="placeholder" v-else>请通过搜索“
 | 
			
		||||
        <strong>手机号或身份证号</strong>
 | 
			
		||||
        ”后选择结算对象
 | 
			
		||||
      </span>
 | 
			
		||||
    </div>
 | 
			
		||||
    <u-modal v-model="show" title="温馨提示" @confirm="confirm" content="该手机号绑定了多个居民,请通过身份证号进行查询"
 | 
			
		||||
             :confirm-style="{fontWeight:800}"></u-modal>
 | 
			
		||||
    <back/>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
  import back from "../../components/AiBack";
 | 
			
		||||
 | 
			
		||||
  export default {
 | 
			
		||||
    name: "search",
 | 
			
		||||
    components: {back},
 | 
			
		||||
    data() {
 | 
			
		||||
      return {
 | 
			
		||||
        keyword: "",
 | 
			
		||||
        show: false,
 | 
			
		||||
        result: null,
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    methods: {
 | 
			
		||||
      selected() {
 | 
			
		||||
        uni.navigateBack({
 | 
			
		||||
          delta: 1,
 | 
			
		||||
          success: () => {
 | 
			
		||||
            uni.$emit('selected',this.result)
 | 
			
		||||
          },
 | 
			
		||||
          fail: (err) => {
 | 
			
		||||
            console.error(err)
 | 
			
		||||
          }
 | 
			
		||||
        })
 | 
			
		||||
      },
 | 
			
		||||
      search() {
 | 
			
		||||
        if (this.keyword == "") {
 | 
			
		||||
          return uni.showToast({
 | 
			
		||||
            title: "请输入搜索关键字",
 | 
			
		||||
            icon: 'none'
 | 
			
		||||
          })
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.$http.post(`/app/appresident/queryFamilyByPhone`, null, {
 | 
			
		||||
          params: {
 | 
			
		||||
            phone: this.keyword
 | 
			
		||||
          }
 | 
			
		||||
        }).then(res => {
 | 
			
		||||
          if (res && res.data) {
 | 
			
		||||
            this.result = res.data
 | 
			
		||||
          }
 | 
			
		||||
        }).catch(e => {
 | 
			
		||||
          this.result = null
 | 
			
		||||
          uni.showToast({
 | 
			
		||||
            title: e,
 | 
			
		||||
            icon: 'none'
 | 
			
		||||
          })
 | 
			
		||||
        })
 | 
			
		||||
      },
 | 
			
		||||
      confirm() {
 | 
			
		||||
        this.show = false
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
  .search {
 | 
			
		||||
    min-height: 100%;
 | 
			
		||||
    background-color: #ffffff;
 | 
			
		||||
 | 
			
		||||
    .search-wrap {
 | 
			
		||||
      width: 100%;
 | 
			
		||||
      box-sizing: border-box;
 | 
			
		||||
      padding: 24px 32px;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .result-body {
 | 
			
		||||
 | 
			
		||||
      .res-item {
 | 
			
		||||
        height: 112px;
 | 
			
		||||
        border-bottom: 1px solid #F5F5F5;
 | 
			
		||||
        box-sizing: border-box;
 | 
			
		||||
        padding: 0 56px;
 | 
			
		||||
        display: flex;
 | 
			
		||||
        align-items: center;
 | 
			
		||||
        justify-content: space-between;
 | 
			
		||||
 | 
			
		||||
        & > span {
 | 
			
		||||
          font-size: 32px;
 | 
			
		||||
          color: #333333;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .placeholder {
 | 
			
		||||
        display: flex;
 | 
			
		||||
        justify-content: center;
 | 
			
		||||
        margin-top: 144px;
 | 
			
		||||
        font-size: 28px;
 | 
			
		||||
        color: #999999;
 | 
			
		||||
 | 
			
		||||
        & > strong {
 | 
			
		||||
          color: #135AB8;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  }
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										337
									
								
								src/pages/supermarket/supermarket.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,337 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <section class="supermarket">
 | 
			
		||||
    <template v-if="Object.keys(list).length">
 | 
			
		||||
      <div class="nav-left">
 | 
			
		||||
        <scroll-view scroll-y style="height: 100%;">
 | 
			
		||||
          <div class="nav-left-item" v-for="(val, key, index) in list" :style="active(key)" :key="index"
 | 
			
		||||
               @click="clickSort(key,index)">
 | 
			
		||||
            {{key}}分区
 | 
			
		||||
            <u-badge size="mini" :count="sortCountList[index]" absolute :offset="[5,5]"></u-badge>
 | 
			
		||||
          </div>
 | 
			
		||||
        </scroll-view>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="nav-right">
 | 
			
		||||
        <scroll-view scroll-y style="height: 100%;">
 | 
			
		||||
          <div class="category-item" v-for="(item,index) in categoryList" :key="index">
 | 
			
		||||
            <img
 | 
			
		||||
              :src="parseObj(item.photo)"
 | 
			
		||||
              class="category-img" alt="">
 | 
			
		||||
            <div class="category-info">
 | 
			
		||||
              <label class="hidden">{{item.merchandiseName}}</label>
 | 
			
		||||
              <span class="score">{{item.costIntegral}}
 | 
			
		||||
                <span>积分</span>
 | 
			
		||||
              </span>
 | 
			
		||||
              <div class="wrap">
 | 
			
		||||
                <div class="lxc-count">
 | 
			
		||||
                  <div class="less" @click="less(item,index)">-</div>
 | 
			
		||||
                  <div class="num">{{item.merchandiseNumber}}</div>
 | 
			
		||||
                  <div class="less" @click="add(item,index)">+</div>
 | 
			
		||||
                </div>
 | 
			
		||||
              </div>
 | 
			
		||||
            </div>
 | 
			
		||||
          </div>
 | 
			
		||||
        </scroll-view>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="footer">
 | 
			
		||||
        <div class="sum">
 | 
			
		||||
          <span>共{{totalCount}}件商品</span>
 | 
			
		||||
          <span>合计:{{totalScore}}
 | 
			
		||||
          <span>积分</span>
 | 
			
		||||
        </span>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="btn" @click="handleSubmit">去结算</div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </template>
 | 
			
		||||
    <AiEmpty v-else></AiEmpty>
 | 
			
		||||
  </section>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
  import AiEmpty from "../../components/AiEmpty/AiEmpty";
 | 
			
		||||
  import {mapState} from "vuex";
 | 
			
		||||
  export default {
 | 
			
		||||
    name: "supermarket",
 | 
			
		||||
    components: {AiEmpty},
 | 
			
		||||
    data() {
 | 
			
		||||
      return {
 | 
			
		||||
        list: {},
 | 
			
		||||
        idx: 0,
 | 
			
		||||
        totalScore: 0,
 | 
			
		||||
        sortCountList: [],
 | 
			
		||||
        mark: 0,
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    onLoad() {
 | 
			
		||||
      this.getList()
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    watch: {
 | 
			
		||||
      list: {
 | 
			
		||||
        handler(val) {
 | 
			
		||||
          let sum = 0
 | 
			
		||||
          Object.keys(val).map(e=>{
 | 
			
		||||
            val[e].map(p=>{
 | 
			
		||||
              if (p.merchandiseNumber != 0) {
 | 
			
		||||
                sum += (p.merchandiseNumber) * (p.costIntegral)
 | 
			
		||||
              }
 | 
			
		||||
            })
 | 
			
		||||
          })
 | 
			
		||||
          this.totalScore = sum
 | 
			
		||||
        },
 | 
			
		||||
        immediate: true,
 | 
			
		||||
        deep: true
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    computed: {
 | 
			
		||||
      ...mapState(['user']),
 | 
			
		||||
      totalCount() {
 | 
			
		||||
        return this.sortCountList.reduce((pre, cur) => (pre + cur), 0)
 | 
			
		||||
      },
 | 
			
		||||
 | 
			
		||||
      categoryList() {
 | 
			
		||||
        return this.idx == 0 ? this.list[Object.keys(this.list)[0]] : this.list[this.idx]
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    methods: {
 | 
			
		||||
      handleSubmit() {
 | 
			
		||||
        if (this.totalCount == 0) {
 | 
			
		||||
          return uni.showToast({
 | 
			
		||||
            title: "您还没有选择商品",
 | 
			
		||||
            icon: 'none'
 | 
			
		||||
          })
 | 
			
		||||
        }
 | 
			
		||||
        let filter = []
 | 
			
		||||
        Object.keys(this.list).map(e => {
 | 
			
		||||
          this.list[e].map(p => {
 | 
			
		||||
            if (p.merchandiseNumber > 0) {
 | 
			
		||||
              filter.push(p)
 | 
			
		||||
            }
 | 
			
		||||
          })
 | 
			
		||||
        })
 | 
			
		||||
        uni.navigateTo({
 | 
			
		||||
          url: "/pages/supermarket/balance?category=" + JSON.stringify(filter)
 | 
			
		||||
        })
 | 
			
		||||
      },
 | 
			
		||||
      active(key) {
 | 
			
		||||
        const flag = key == this.idx
 | 
			
		||||
        return {
 | 
			
		||||
          borderLeft: flag ? '3px solid #1D58FE' : '',
 | 
			
		||||
          background: flag ? 'linear-gradient(270deg, #FFFFFF 0%, #FFFFFF 77%, #E7EAFA 100%)' : ''
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      add(item, index) {
 | 
			
		||||
        this.list[this.idx][index]["merchandiseNumber"] = this.list[this.idx][index]["merchandiseNumber"] + 1
 | 
			
		||||
        this.$set(this.sortCountList, this.mark, this.list[this.idx]?.reduce((pre,curr)=>{
 | 
			
		||||
          return (pre + curr.merchandiseNumber)
 | 
			
		||||
        },0))
 | 
			
		||||
      },
 | 
			
		||||
      less(item, index) {
 | 
			
		||||
        if (item.merchandiseNumber > 0) {
 | 
			
		||||
          this.list[this.idx][index]["merchandiseNumber"] = this.list[this.idx][index]["merchandiseNumber"] - 1
 | 
			
		||||
          this.$set(this.sortCountList, this.mark, this.list[this.idx]?.reduce((pre,curr)=>{
 | 
			
		||||
            return (pre + curr.merchandiseNumber)
 | 
			
		||||
          },0))
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      clickSort(key, index) {
 | 
			
		||||
        this.mark = index
 | 
			
		||||
        this.idx = key.toString()
 | 
			
		||||
      },
 | 
			
		||||
      parseObj(json) {
 | 
			
		||||
        return JSON.parse(json || '[]')[0]?.url
 | 
			
		||||
      },
 | 
			
		||||
      getList() {
 | 
			
		||||
        this.$http.post(`/app/appvillagerintegralmerchandise/listByIntegral`, null, {
 | 
			
		||||
          params: {
 | 
			
		||||
            areaId: this.user?.areaId
 | 
			
		||||
          }
 | 
			
		||||
        }).then(res => {
 | 
			
		||||
          if (res && res.data) {
 | 
			
		||||
            Object.keys(res.data).map(e => {
 | 
			
		||||
              res.data[e].map(p => {
 | 
			
		||||
                p.merchandiseNumber = 0
 | 
			
		||||
              })
 | 
			
		||||
            })
 | 
			
		||||
            this.list = res.data
 | 
			
		||||
            this.idx = Object.keys(res.data)[0]
 | 
			
		||||
            this.sortCountList = Array(Object.keys(res.data).length).fill(0)
 | 
			
		||||
          }
 | 
			
		||||
        })
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
  }
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
  uni-page-body{
 | 
			
		||||
    background-color: #ffffff;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .supermarket {
 | 
			
		||||
    background-color: #ffffff;
 | 
			
		||||
    display: flex;
 | 
			
		||||
    justify-content: space-between;
 | 
			
		||||
    padding-bottom: 104px;
 | 
			
		||||
 | 
			
		||||
    .nav-left {
 | 
			
		||||
      width: 168px;
 | 
			
		||||
      height: 100%;
 | 
			
		||||
 | 
			
		||||
      .nav-left-item {
 | 
			
		||||
        height: 104px;
 | 
			
		||||
        background: #FAF9FB;
 | 
			
		||||
        display: flex;
 | 
			
		||||
        align-items: center;
 | 
			
		||||
        justify-content: center;
 | 
			
		||||
        font-size: 28px;
 | 
			
		||||
        color: #333333;
 | 
			
		||||
        border-top: 1px solid #D8E5FF;
 | 
			
		||||
        border-left: 2px solid transparent;
 | 
			
		||||
        position: relative;
 | 
			
		||||
 | 
			
		||||
        &:nth-last-child {
 | 
			
		||||
          border-bottom: 1px solid #D8E5FF;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .nav-right {
 | 
			
		||||
      width: calc(100% - 168px - 24px);
 | 
			
		||||
      height: 100%;
 | 
			
		||||
 | 
			
		||||
      .category-item {
 | 
			
		||||
        height: 264px;
 | 
			
		||||
        box-sizing: border-box;
 | 
			
		||||
        padding: 28px 32px 44px 30px;
 | 
			
		||||
        display: flex;
 | 
			
		||||
 | 
			
		||||
        .category-img {
 | 
			
		||||
          width: 192px;
 | 
			
		||||
          height: 192px;
 | 
			
		||||
          border: 1px solid #F6F6F6;
 | 
			
		||||
          flex-shrink: 0;
 | 
			
		||||
          margin-right: 30px;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .category-info {
 | 
			
		||||
          width: 100%;
 | 
			
		||||
          display: flex;
 | 
			
		||||
          flex-direction: column;
 | 
			
		||||
          justify-content: space-between;
 | 
			
		||||
 | 
			
		||||
          & > label {
 | 
			
		||||
            font-size: 30px;
 | 
			
		||||
            font-weight: 800;
 | 
			
		||||
            color: #333333;
 | 
			
		||||
            line-height: 42px;
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          .score {
 | 
			
		||||
            font-size: 40px;
 | 
			
		||||
            font-weight: 600;
 | 
			
		||||
            color: #FA4A51;
 | 
			
		||||
            line-height: 40px;
 | 
			
		||||
 | 
			
		||||
            & > span {
 | 
			
		||||
              font-size: 24px;
 | 
			
		||||
              color: #FA4A51;
 | 
			
		||||
              margin-left: 8px;
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          .wrap {
 | 
			
		||||
            display: flex;
 | 
			
		||||
            justify-content: flex-end;
 | 
			
		||||
            .lxc-count{
 | 
			
		||||
              display: flex;
 | 
			
		||||
              align-items: center;
 | 
			
		||||
              justify-content: center;
 | 
			
		||||
              .less{
 | 
			
		||||
                width: 40px;
 | 
			
		||||
                height: 40px;
 | 
			
		||||
                font-size: 20px;
 | 
			
		||||
                display: flex;
 | 
			
		||||
                align-items: center;
 | 
			
		||||
                justify-content: center;
 | 
			
		||||
                font-size: 36px;
 | 
			
		||||
                font-weight: 500;
 | 
			
		||||
                color: #333333;
 | 
			
		||||
              }
 | 
			
		||||
 | 
			
		||||
              .num{
 | 
			
		||||
                width: 89px;
 | 
			
		||||
                height: 61px;
 | 
			
		||||
                display: flex;
 | 
			
		||||
                align-items: center;
 | 
			
		||||
                justify-content: center;
 | 
			
		||||
                background: #F6F6F6;
 | 
			
		||||
                border-radius: 10px;
 | 
			
		||||
                font-size: 28px;
 | 
			
		||||
                font-weight: 400;
 | 
			
		||||
                color: #333333;
 | 
			
		||||
                margin: 0 16px;
 | 
			
		||||
              }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .footer {
 | 
			
		||||
      display: flex;
 | 
			
		||||
      align-items: center;
 | 
			
		||||
      width: 100%;
 | 
			
		||||
      background-color: #ffffff;
 | 
			
		||||
      z-index: 100;
 | 
			
		||||
      height: 104px;
 | 
			
		||||
      box-shadow: 0px -2px 8px 0px rgba(214, 214, 214, 0.5);
 | 
			
		||||
      position: fixed;
 | 
			
		||||
      left: 0;
 | 
			
		||||
      bottom: 0;
 | 
			
		||||
 | 
			
		||||
      .sum {
 | 
			
		||||
        width: calc(100% - 212px);
 | 
			
		||||
        box-sizing: border-box;
 | 
			
		||||
        padding: 30px;
 | 
			
		||||
        display: flex;
 | 
			
		||||
        justify-content: space-between;
 | 
			
		||||
 | 
			
		||||
        & > span:nth-child(1), span:nth-child(2) {
 | 
			
		||||
          font-size: 32px;
 | 
			
		||||
          font-weight: 400;
 | 
			
		||||
          color: #F94246;
 | 
			
		||||
 | 
			
		||||
          & > span {
 | 
			
		||||
            font-size: 24px;
 | 
			
		||||
            margin-left: 12px;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .btn {
 | 
			
		||||
        width: 212px;
 | 
			
		||||
        height: 100%;
 | 
			
		||||
        background-color: #1365DD;
 | 
			
		||||
        font-size: 36px;
 | 
			
		||||
        font-weight: 500;
 | 
			
		||||
        color: #FFFFFF;
 | 
			
		||||
        display: flex;
 | 
			
		||||
        align-items: center;
 | 
			
		||||
        justify-content: center;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .hidden {
 | 
			
		||||
      overflow: hidden;
 | 
			
		||||
      text-overflow: ellipsis;
 | 
			
		||||
      display: -webkit-box;
 | 
			
		||||
      -webkit-box-orient: vertical;
 | 
			
		||||
      -webkit-line-clamp: 2;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										87
									
								
								src/pages/videoSurveillance/monitorDetail.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,87 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <section class="monitorDetail">
 | 
			
		||||
    <div class="videoBox">
 | 
			
		||||
      <iframe ref="monitorIns" :style="style" :src="monitor.url" allow="autoplay *; microphone *; fullscreen *"
 | 
			
		||||
              allowfullscreen allowtransparency allowusermedia frameBorder="no"/>
 | 
			
		||||
    </div>
 | 
			
		||||
  </section>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import AiFixedBtn from "../../components/AiFixedBtn";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: "monitorDetail",
 | 
			
		||||
  components: {AiFixedBtn},
 | 
			
		||||
  data() {
 | 
			
		||||
    return {
 | 
			
		||||
      style: {},
 | 
			
		||||
      monitor: {}
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  mounted() {
 | 
			
		||||
    this.$nextTick(() => {
 | 
			
		||||
      this.detectOrient()
 | 
			
		||||
    })
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  methods: {
 | 
			
		||||
    getDetail(deviceId) {
 | 
			
		||||
      deviceId && this.$http.post("/app/appzyvideoequipment/getWebSdkUrl", null, {
 | 
			
		||||
        params: {deviceId}
 | 
			
		||||
      }).then(res => {
 | 
			
		||||
        if (res?.data) {
 | 
			
		||||
          this.monitor = JSON.parse(res.data)
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    detectOrient() {
 | 
			
		||||
      var width = document.querySelector('.monitorDetail').clientWidth
 | 
			
		||||
      var height = document.querySelector('.monitorDetail').clientHeight
 | 
			
		||||
      if (width >= height) { // 竖屏
 | 
			
		||||
        this.style = {
 | 
			
		||||
          width: '100%',
 | 
			
		||||
          height: '100%',
 | 
			
		||||
          transform: 'rotate(0eg)',
 | 
			
		||||
          transformOrigin: `0 0`
 | 
			
		||||
        }
 | 
			
		||||
      } else {
 | 
			
		||||
        this.style = {
 | 
			
		||||
          width: height + 'px',
 | 
			
		||||
          height: width + 'px',
 | 
			
		||||
          transform: 'rotate(90deg)',
 | 
			
		||||
          transformOrigin: `${width / 2}px ${width / 2}px`
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  onLoad(params) {
 | 
			
		||||
    this.getDetail(params.id)
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
.monitorDetail {
 | 
			
		||||
  position: fixed;
 | 
			
		||||
  left: 0;
 | 
			
		||||
  right: 0;
 | 
			
		||||
  top: 0;
 | 
			
		||||
  bottom: 0;
 | 
			
		||||
  width: 100vw;
 | 
			
		||||
  height: 100vh;
 | 
			
		||||
  background: #000;
 | 
			
		||||
  color: #fff;
 | 
			
		||||
 | 
			
		||||
  .videoBox {
 | 
			
		||||
    width: 100vw;
 | 
			
		||||
    height: 100vh;
 | 
			
		||||
 | 
			
		||||
    iframe {
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										144
									
								
								src/pages/videoSurveillance/videoSurveillance.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,144 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <section class="videoSurveillance">
 | 
			
		||||
    <ai-top-fixed>
 | 
			
		||||
      <div class="header" flex>
 | 
			
		||||
        <div flex v-for="(node,i) in nodes" :key="i">
 | 
			
		||||
          <div :class="{current:isCurrent(i)}" v-text="node.nodeName" @click="gotoNode(node,i)"/>
 | 
			
		||||
          <u-icon v-if="!isCurrent(i)" name="arrow-right" color="#ddd"/>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </ai-top-fixed>
 | 
			
		||||
    <div class="list">
 | 
			
		||||
      <div class="item" v-for="row in monitors" :key="row.nodeId" :class="{online:!row.online}">
 | 
			
		||||
        <template v-if="!!row.deviceId">
 | 
			
		||||
          <img src="../resourcesManage/img/video-img.png" alt="" class="videoIcon" @click="showMonitor(row)">
 | 
			
		||||
          <div class="area-name" v-text="row.deviceName" @click="showMonitor(row)"/>
 | 
			
		||||
          <div class="deviceStatus" v-text="!row.online?'在线':'离线'" @click="showMonitor(row)"/>
 | 
			
		||||
        </template>
 | 
			
		||||
        <template v-else>
 | 
			
		||||
          <div class="area-name" v-text="row.nodeName" @click="getMore(row)"/>
 | 
			
		||||
          <u-icon name="arrow-right" color="#ddd" @click="getMore(row)"/>
 | 
			
		||||
        </template>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
  </section>
 | 
			
		||||
</template>
 | 
			
		||||
<script>
 | 
			
		||||
 | 
			
		||||
import AiTopFixed from "../../components/AiTopFixed";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: "videoSurveillance",
 | 
			
		||||
  components: {AiTopFixed},
 | 
			
		||||
  data() {
 | 
			
		||||
    return {
 | 
			
		||||
      nodes: [
 | 
			
		||||
        {nodeName: "首页"}
 | 
			
		||||
      ],
 | 
			
		||||
      monitors: []
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    getMonitors(nodeId, queryType = 0) {
 | 
			
		||||
      this.monitors = []
 | 
			
		||||
      this.$http.post("/app/appzyvideoequipment/getTree", {
 | 
			
		||||
        nodeId, queryType
 | 
			
		||||
      }).then(res => {
 | 
			
		||||
        if (res?.data) {
 | 
			
		||||
          this.monitors = JSON.parse(res.data)?.[queryType == 0 ? 'node' : 'device'] || []
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
    },
 | 
			
		||||
    getMore(row) {
 | 
			
		||||
      this.nodes.push(row)
 | 
			
		||||
      this.getMonitors(row.nodeId, row.hasChild == 1 ? 0 : 1)
 | 
			
		||||
    },
 | 
			
		||||
    showMonitor(row) {
 | 
			
		||||
      uni.navigateTo({url: `./monitorDetail?id=${row.deviceId}`})
 | 
			
		||||
    },
 | 
			
		||||
    isCurrent(index) {
 | 
			
		||||
      return index == Math.max(this.nodes?.length - 1, 0)
 | 
			
		||||
    },
 | 
			
		||||
    gotoNode(node, index) {
 | 
			
		||||
      this.nodes.splice(index + 1)
 | 
			
		||||
      this.getMonitors(node.nodeId)
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  created() {
 | 
			
		||||
    this.getMonitors()
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
.videoSurveillance {
 | 
			
		||||
  ::v-deep .placeholder {
 | 
			
		||||
    margin-bottom: 8px;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .header {
 | 
			
		||||
    color: #666;
 | 
			
		||||
 | 
			
		||||
    .current {
 | 
			
		||||
      color: #4E8EEE;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .list {
 | 
			
		||||
    padding-left: 32px;
 | 
			
		||||
    background: #FFF;
 | 
			
		||||
 | 
			
		||||
    .item {
 | 
			
		||||
      width: 100%;
 | 
			
		||||
      height: 104px;
 | 
			
		||||
      border-bottom: 1px solid #DDD;
 | 
			
		||||
      padding: 0 32px 0 0;
 | 
			
		||||
      box-sizing: border-box;
 | 
			
		||||
      display: flex;
 | 
			
		||||
      align-items: center;
 | 
			
		||||
 | 
			
		||||
      &.online {
 | 
			
		||||
        .videoIcon {
 | 
			
		||||
          filter: none;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .deviceStatus {
 | 
			
		||||
          color: #4E8EEE;
 | 
			
		||||
          background: #E7F1FD;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .videoIcon {
 | 
			
		||||
        width: 48px;
 | 
			
		||||
        height: 32px;
 | 
			
		||||
        margin-right: 8px;
 | 
			
		||||
        filter: grayscale(100%);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .area-name {
 | 
			
		||||
        font-size: 34px;
 | 
			
		||||
        font-weight: 500;
 | 
			
		||||
        color: #333;
 | 
			
		||||
        flex: 1;
 | 
			
		||||
        min-width: 0;
 | 
			
		||||
        white-space: nowrap;
 | 
			
		||||
        overflow: hidden;
 | 
			
		||||
        text-overflow: ellipsis;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .deviceStatus {
 | 
			
		||||
        margin-left: 8px;
 | 
			
		||||
        height: 22px;
 | 
			
		||||
        padding: 0 8px;
 | 
			
		||||
        line-height: 22px;
 | 
			
		||||
        font-size: 13px;
 | 
			
		||||
        color: #666;
 | 
			
		||||
        background: #E9E9E9;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      &:last-of-type {
 | 
			
		||||
        border-bottom: none;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||