ll
liukangdong
2025-02-18 031d0f428f58b008f7a59476fcf3e6ba86d10048
ll
已添加16个文件
已删除1个文件
已修改6个文件
37725 ■■■■■ 文件已修改
admin/package-lock.json 24847 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/package.json 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/public/index.html 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/assets/style/style.scss 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/assets/style/variables.scss 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/components/base/BasePageTemp.vue 37 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/components/common/QueryForm/index.js 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/components/common/QueryForm/queryForm.vue 233 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/components/common/RichEditor.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/layouts/Breadcrumb.vue 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/views/combo/components/ComboDetail.vue 402 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/views/combo/components/Edit.vue 229 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/views/combo/components/OrderDetail.vue 105 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/views/combo/components/config.js 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/views/combo/index.vue 165 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/views/combo/order.vue 156 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/views/combo/record.vue 494 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/views/operation/components/Map.vue 73 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/views/operation/components/SitesWindow.vue 90 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/views/operation/components/TramEdit.vue 69 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/views/operation/site.vue 109 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/views/operation/tram.vue 109 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/yarn.lock 10478 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/package-lock.json
ÎļþÌ«´ó
admin/package.json
@@ -4,6 +4,7 @@
  "private": true,
  "scripts": {
    "serve": "vue-cli-service serve",
    "dev": "vue-cli-service serve",
    "build:pro": "vue-cli-service build",
    "build:dev": "vue-cli-service build --mode staging",
    "lint": "vue-cli-service lint",
@@ -50,7 +51,7 @@
    "eslint-plugin-standard": "^4.0.0",
    "eslint-plugin-vue": "^6.2.2",
    "lint-staged": "^9.5.0",
      "node-sass": "^4.14.1",
    "node-sass": "^4.14.1",
    "vue-cli-plugin-element-ui": "~1.1.4",
    "vue-template-compiler": "^2.6.14"
  },
admin/public/index.html
@@ -18,6 +18,7 @@
  <div id="app"></div>
  <!-- built files will be auto injected -->
</body>
<script charset="utf-8" src="https://map.qq.com/api/gljs?libraries=tools&v=1.exp&key=HLMBZ-BQ6LM-AY46S-6B5SN-C3DJT-MVBKL"></script>
<script>
</script>
admin/src/assets/style/style.scss
@@ -51,7 +51,52 @@
.el-transfer__buttons {
  padding: 0 16px !important;
}
.main_app{
  padding: 6px 16px;
}
.flex1{
  flex: 1;
}
.primaryColor{
  color: $primary-color;
}
.pointer{
  cursor: pointer;
}
.w200{
  width: 200px !important;
}
.w400{
  width: 400px !important;
}
.w100{
  width: 100px !important;
}
.ml16{
  margin-left: 16px;
}
.ml10{
  margin-left: 10px;
}
.mr16{
  margin-right: 16px;
}
.mr10{
  margin-right: 10px;
}
.placeholder9{
  color: #999999;
  font-size: 12px;
}
.df_ac{
  display: flex;
  align-items: center;
}
.table_btns{
  background-color: #fff;
  padding: 16px 16px 10px 16px;
}
.table-header {
  background-color: #F5F6F8!important;
  th {
admin/src/assets/style/variables.scss
@@ -1,5 +1,6 @@
// ä¸»è‰²è°ƒ
$primary-color: #216EEE;
$primaryColor: #216EEE;
$primary-title-start-color: #3582ff;
$primary-title-color: #216EcE;
$primary-color-sel: #0046c6;
admin/src/components/base/BasePageTemp.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,37 @@
<script>
import Pagination from '@/components/common/Pagination'
import QueryForm from '@/components/common/QueryForm'
export default {
  name: 'BasePageTemp',
  components: {
    Pagination,
    QueryForm,
  },
  data () {
    return {
      loading: false,
      pagination: {
        pageSize: 10,
        page: 1,
        total: 0
      },
      filters: {},
      list: [],
      total: 0,
    }
  },
  methods: {
    getList(){},
    clear() {
      this.filters = {}
      this.pagination.pageSize = 10
      this.pagination.page = 1
      this.getList()
    },
    handleSizeChange(capacity) {
      this.pagination.pageSize = capacity
      this.getList()
    }
  }
}
</script>
admin/src/components/common/QueryForm/index.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,3 @@
import QueryForm from './queryForm.vue'
export default QueryForm
admin/src/components/common/QueryForm/queryForm.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,233 @@
<template>
  <div class="doumee-filter">
    <el-form inline label-suffix=":" @submit.native.prevent>
      <template v-for="(item, index) in queryFormConfig.formItems">
        <el-form-item v-if="item.type === 'input' && (showZk || index < listLength)" :label="item.label" :key="item.filed">
          <el-input v-model="searchForm[item.filed]"
            :clearable="(item.clearable !== null && item.clearable !== undefined && item.clearable !== '') ? item.clearable : true"
            :placeholder="item.label" class="w200"
            @change="changeForm(item.filed)" @keyup.enter.native="handlekeyup(item.keyup || false)" />
        </el-form-item>
        <el-form-item v-if="item.type === 'moneySelect' && (showZk || index < listLength)" :label="item.label" :key="item.label">
          <el-input v-model="searchForm[item.filedStrt]"
            :clearable="(item.clearable !== null && item.clearable !== undefined && item.clearable !== '') ? item.clearable : true"
            :placeholder="item.start" style="width: 150px" />
          <div class="date-division-line" style="margin-left: 10px;margin-bottom: 0;">~</div>
          <el-input v-model="searchForm[item.filedEnd]"
            :clearable="(item.clearable !== null && item.clearable !== undefined && item.clearable !== '') ? item.clearable : true"
            :placeholder="item.end" style="width: 150px" />
        </el-form-item>
        <el-form-item v-if="item.type === 'select' && (showZk || index < listLength)" :label="item.label" :key="item.filed">
          <el-select v-model="searchForm[item.filed]" :filterable="item.filterable || true"
            :clearable="(item.clearable !== null && item.clearable !== undefined && item.clearable !== '') ? item.clearable : true"
            :placeholder="item.label" class="w200"
            @change="changeForm(item.filed)">
            <el-option v-for="opt, i in item.options" :key="i" :value="item.valueCode ? opt[item.valueCode] : opt.value"
              :label="item.labelCode ? opt[item.labelCode] : opt.label" />
          </el-select>
        </el-form-item>
        <el-form-item v-if="item.type === 'date' && (showZk || index < listLength)" :label="item.label" :key="item.filed">
          <el-date-picker v-model="searchForm[item.filed]" type="date" value-format="yyyy-MM-dd" class="w200"
            :clearable="(item.clearable !== null && item.clearable !== undefined && item.clearable !== '') ? item.clearable : true"
            :placeholder="item.label" :picker-options="item.pickerOptions || {}"
            @change="changeForm(item.filed)" />
        </el-form-item>
        <el-form-item v-if="item.type === 'daterange' && (showZk || index < listLength)" :label="item.label" :key="item.filed">
          <el-date-picker v-model="searchForm[item.filed]" value-format="yyyy-MM-dd" type="daterange"
            range-separator="至"
            :clearable="(item.clearable !== null && item.clearable !== undefined && item.clearable !== '') ? item.clearable : true"
            :start-placeholder="item.start || ''" :end-placeholder="item.end || ''"
            :picker-options="item.pickerOptions || {}" class="w400" @change="changeForm(item.filed)" />
        </el-form-item>
        <el-form-item v-if="item.type === 'timePicker' && (showZk || index < listLength)" :label="item.label" :key="item.filed">
          <el-time-picker v-model="searchForm[item.filed]" is-range range-separator="至" format="HH:mm"
            value-format="HH:mm" start-placeholder="开始时间" end-placeholder="结束时间" placeholder="选择时间范围" class="w400"
            @change="changeForm(item.filed)" />
        </el-form-item>
        <el-form-item v-if="item.type === 'datetimerange' && (showZk || index < listLength)" :label="item.label" :key="item.filed">
          <el-date-picker v-model="searchForm[item.filed]" format="yyyy-MM-dd HH:mm:ss"
            value-format="yyyy-MM-dd HH:mm:ss" type="datetimerange" :default-time="['00:00:00', '23:59:59']"
            :picker-options="item.pickerOptions || pickerOptions" range-separator="至"
            :clearable="(item.clearable !== null && item.clearable !== undefined && item.clearable !== '') ? item.clearable : true"
            :start-placeholder="item.start || '开始时间'" :end-placeholder="item.end || '结束时间'" class="w400"
            @change="changeForm(item.filed)" />
        </el-form-item>
        <el-form-item v-if="item.type === 'slot' && (showZk || index < listLength)" :label="item.label" :key="item.filed">
          <slot :name="item.filed" />
        </el-form-item>
      </template>
      <!-- æ“ä½œ -->
      <el-form-item>
        <el-button style="width: 56px" type="primary" @click="handleQuery">搜索</el-button>
        <el-button style="width: 56px" v-if="showQk" @click="clear">重置</el-button>
        <slot name="btns" />
        <template v-if="queryFormConfig.formItems.length > listLength">
          <el-button v-if="!showZk" type="text" @click="zkBtn">展开<i
              class="el-icon-caret-bottom primaryColor" /></el-button>
          <el-button v-if="showZk" type="text" @click="zkBtn">收起<i class="el-icon-caret-top primaryColor" /></el-button>
        </template>
      </el-form-item>
    </el-form>
  </div>
</template>
<script>
export default {
  props: {
    value: {
      type: Object,
      default: () => { }
    },
    showQk: {
      type: Boolean,
      default: true
    },
    listLength: {
      type: Number,
      default: 6
    },
    queryFormConfig: {
      type: Object,
      default: () => { }
    }
  },
  data() {
    return {
      showZk: false,
      pickerOptions: {
        shortcuts: [{
          text: '近7天',
          onClick(picker) {
            const end = new Date()
            const start = new Date()
            start.setTime(end.getTime() - 3600 * 1000 * 24 * 6)
            picker.$emit('pick', [start, end])
          }
        },
        {
          text: '近30天',
          onClick(picker) {
            const end = new Date()
            const start = new Date()
            start.setTime(end.getTime() - 3600 * 1000 * 24 * 29)
            picker.$emit('pick', [start, end])
          }
        },
        {
          text: '近60天',
          onClick(picker) {
            const end = new Date()
            const start = new Date()
            start.setTime(end.getTime() - 3600 * 1000 * 24 * 59)
            picker.$emit('pick', [start, end])
          }
        },
        {
          text: '近90天',
          onClick(picker) {
            const end = new Date()
            const start = new Date()
            start.setTime(end.getTime() - 3600 * 1000 * 24 * 89)
            picker.$emit('pick', [start, end])
          }
        }],
        disabledDate(time) {
          var curDate = new Date(new Date().toLocaleDateString()).getTime()
          var preDate = new Date(curDate + 24 * 60 * 60 * 1000 - 1)
          return time.getTime() > preDate
        }
      }
    }
  },
  emits: ['input', 'handleQuery', 'clear'],
  computed: {
    searchForm: {
      get() {
        return this.value
      },
      set(value) {
        this.$emit('input', value)
      }
    }
  },
  methods: {
    handleQuery() {
      this.$emit('handleQuery')
    },
    handlekeyup(pd) {
      if (pd) {
        this.$emit('handleQuery')
      }
    },
    changeForm(filed) {
      this.$emit('changeForm', filed)
    },
    zkBtn() {
      this.showZk = !this.showZk
      this.$emit('zkBtn', this.zk)
    },
    clear() {
      this.$emit('clear')
    }
  }
}
</script>
<style lang="scss" scoped>
.doumee-filter {
  display: flex;
  align-items: center;
  position: relative;
  flex-wrap: wrap;
  align-items: center;
  background-color: #fff;
  border-bottom: 10px solid #f7f8f9;
  /* margin: 0 -20px; */
  padding: 16px 16px 0 16px;
  .el-input,
  .el-select {
    width: 200px;
    margin-right: 16px;
    margin-bottom: 16px;
    height: 36px;
    .el-input__inner {
      /* color: $textColor; */
      padding: 0 16px;
    }
  }
  .el-date-editor {
    width: 200px;
    margin-right: 16px;
    margin-bottom: 16px;
    .el-input__inner {
      padding-left: 30px;
    }
  }
  .el-button {
    margin-bottom: 16px;
  }
  .el-form-item {
    margin-bottom: 16px;
    margin-right: 16px;
    .el-input,
    .el-select,
    .el-date-editor {
      margin-right: 0;
    }
    .el-input,
    .el-select,
    .el-date-editor,
    .el-button {
      margin-bottom: 0;
    }
  }
}
</style>
admin/src/components/common/RichEditor.vue
@@ -143,7 +143,7 @@
      this.editor = Object.seal(editor)
    },
    onChange (editor) {
      console.log(this.html);
      // console.log(this.html);
      // debugger
      if (!this.html||this.content.content==this.html) {
        return
admin/src/layouts/Breadcrumb.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,40 @@
<template>
  <div class="table-header">
    <el-breadcrumb separator="/">
      <el-breadcrumb-item v-for="path in paths" :key="path">{{ path }}</el-breadcrumb-item>
    </el-breadcrumb>
  </div>
</template>
<script>
export default {
  computed: {
    paths() {
      return this.$route.meta.paths
    }
  }
}
</script>
<style lang="scss" scoped>
.table-header {
  overflow: hidden;
  padding: 6px 16px 12px;
  flex-shrink: 0;
  // é¡µé¢è·¯å¾„
  .el-breadcrumb {
    .el-breadcrumb__item {
      .el-breadcrumb__inner {
        color: #ABB2BE;
        font-size: 12px;
      }
      &:last-of-type .el-breadcrumb__inner {
        color: #606263;
        font-size: 14px;
      }
    }
  }
}
</style>
admin/src/views/combo/components/ComboDetail.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,402 @@
<template>
  <GlobalWindow title="套餐详情" :visible.sync="isShowModal" :confirm-working="isLoading" width="1000px" @close="close"
    @confirm="close">
    <div class="detail_header">
      <div class="sp_bew">
        <div class="left">
          <el-image v-if="detail.fullImgurl" :src="detail.fullImgurl" class="img" />
          <div class="title_wrap">
            <div>
              <span class="title">{{ detail.name }}</span>
              <span class="status">{{ detail.status === '1' ? '已启用' : '禁用' }}</span>
            </div>
            <div class="placeholder9 mt10">每日销售限量:{{ detail.circulationDay }}</div>
          </div>
        </div>
        <div class="right">
          <div class="item">
            <div class="key">总发放数量</div>
            <div class="value">{{ detail.circulationAll || '-' }}</div>
          </div>
          <div class="item">
            <div class="key">已销售数量</div>
            <div class="value">{{ detail.sellNum }}</div>
          </div>
          <div class="item">
            <div class="key">剩余数量</div>
            <div v-if="detail.circulationAll" class="value">{{ detail.surplusDay }}</div>
            <div v-else class="value">{{ detail.surplusDay || '-' }}</div>
          </div>
        </div>
      </div>
      <div class="createTime_wrap">
        <span class="item">创建时间:{{ detail.createTime }}</span>
        <span class="item">创建人:{{ detail.creator }}</span>
        <span class="item">最后更新时间:{{ detail.editTime }}</span>
        <span class="item">更新人:{{ detail.editor }}</span>
      </div>
    </div>
    <div class="separate" />
    <div class="property-title">套餐属性</div>
    <div class="line">
      <div class="key">套餐名称:</div>
      <div class="value">{{ detail.name }}</div>
    </div>
    <div class="line">
      <div class="key">套餐类型:</div>
      <div v-if="detail.mealsType == '0'" class="value">期限卡</div>
    </div>
    <div class="line">
      <div class="key">{{ detail.mealsType == '1' || detail.mealsType == '4' ? '每日骑行限制:' : '套餐次数:' }}</div>
      <div v-if="detail.mealsType == '1' || detail.mealsType == '4'" class="value">
        <span>{{ detail.inOutNum || '不限制' }}</span>
      </div>
      <div v-else class="value"><span>{{ detail.nums }}</span></div>
    </div>
    <div class="line">
      <div class="key">使用说明:</div>
      <div class="value">
        <div>{{ detail.content }}</div>
      </div>
    </div>
    <div class="property-title">适用规则</div>
    <div class="line">
      <div class="key">销售时间段:</div>
      <div class="value">{{ detail.circulationAll || '不限量' }}</div>
    </div>
    <div class="line">
      <div class="key">使用时间:</div>
      <div class="value">{{ detail.circulationDay }}</div>
    </div>
    <div class="line">
      <div class="key">适用范围:</div>
      <div class="value">{{ detail.useVenue }}</div>
    </div>
    <div class="line">
      <div class="key">适用项目:</div>
      <div class="value">{{ detail.useProject }}</div>
    </div>
    <div class="line">
      <div class="key">总限额:</div>
      <div class="value">{{ detail.useClassInfo || '不限制' }}</div>
    </div>
    <div class="line">
      <div class="key">每日限额:</div>
      <div class="value">{{ detail.useTeacherInfo || '不限额' }}</div>
    </div>
  </GlobalWindow>
</template>
<script>
// import { comboDetailPost, mealsCancelUse } from '@/api'
// import dayjs from 'dayjs'
import GlobalWindow from '@/components/common/GlobalWindow'
export default {
  name: 'ComboDetail',
  components: {
    GlobalWindow
  },
  data() {
    return {
      isShowModal: false,
      isLoading: false,
      activeTab: '0',
      detail: {},
      pagination: {
        page: 1,
        rows: 10
      },
      totalCount: 0,
      dataList: [],
      tableLoading: false
    }
  },
  created() {
    // this.detail = this.$route.query
    // this.comboDetail()
  },
  methods: {
    mealsCancelUseBtn(businessId, mealsMemberId) {
      const that = this
      this.$alert('确定要撤销使用?', '撤销使用', {
        confirmButtonText: '确定',
        callback: action => {
          if (action === 'confirm') {
            mealsCancelUse({
              param: {
                businessId, mealsMemberId
              }
            }).then((res) => {
              if (res.errorCode === '000000') {
                that.$message.success('撤销使用成功')
                that.comboDetail()
              }
            })
          }
        }
      })
    },
    getDetail(detail) {
      const { activeTab, pagination } = this
      const param = {
        listType: activeTab,
        type: detail.type,
        id: detail.id
      }
      this.tableLoading = true
      comboDetailPost({ pagination, param }).then(res => {
        this.tableLoading = false
        this.dataList = res.record.data || []
        this.totalCount = res.record.count || 0
        this.detail = { ...detail, useProject: res.record.useProject }
        this.$nextTick(() => {
          this.$refs.tableo.doLayout()
        })
      }, () => {
        this.tableLoading = false
      })
    },
    tabClick(val) {
      this.comboDetail(this.detail)
    },
    goBack() {
      this.$router.replace(`/combo/salesRecord`)
    },
    close() {
      this.isShowModal = false
      this.$emit('close')
    },
    currentPageChange(val) {
      this.pagination.page = val
      this.comboDetail()
    },
    pageSizeChange(val) {
      this.pagination.rows = val
      this.comboDetail()
    }
  }
}
</script>
<style lang="scss" scoped>
@import "@/assets/style/variables.scss";
.line {
  display: flex;
  align-items: center;
  margin-bottom: 20px;
  font-size: 14px;
  // padding-left: 16px;
  .key {
    color: #666666;
    width: 100px;
    text-align: right;
  }
  .value {
    color: #222222;
  }
}
.detail_header {
  font-size: 14px;
  .sp_bew {
    display: flex;
    justify-content: space-between;
    .left {
      display: flex;
      .img {
        width: 50px;
        height: 50px;
        margin-right: 20px;
      }
      .title {
        font-size: 18px;
        font-weight: 600;
        color: #222222;
      }
      .status {
        border-radius: 2px;
        border: 1px solid $primaryColor;
        color: $primaryColor;
        margin-left: 10px;
      }
    }
    .right {
      display: flex;
      background-color: #F4F7FC;
      border-radius: 2px;
      .item {
        padding: 14px 20px;
        .key {
          font-size: 12px;
          color: #666666;
        }
        .value {
          margin-top: 8px;
          color: #222222;
          font-weight: 600;
        }
      }
    }
  }
  .createTime_wrap {
    display: flex;
    /* justify-content: flex-end; */
    margin: 16px 0;
    .item {
      margin-right: 30px;
      color: #999999;
    }
  }
}
.separate {
  height: 1px;
  margin: 20px -20px;
  padding: 0 20px;
  background-color: #DFE2E8;
}
.tip {
  font-size: 14px;
  line-height: 1.5;
  color: #333;
}
.property-title{
  margin-bottom: 16px;
  color: $primaryColor;
}
.device-uploader {
  width: 80px;
  height: 80px;
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: #fff;
  cursor: pointer;
  border: 1px dashed #ccc;
  border-radius: 8px;
  transition: all 0.3s;
  margin-right: 20px;
  &:hover {
    border-color: $primaryColor;
    .uploader-icon {
      color: $primaryColor;
    }
  }
  ::v-deep .el-upload {
    width: 100%;
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    position: relative;
    .file {
      width: 100%;
      height: 100%;
      position: absolute;
      top: 0;
      left: 0;
      background-size: contain;
      background-position: center;
      background-repeat: no-repeat;
      border-radius: 8px;
      display: flex;
      align-items: center;
      justify-content: center;
      .delete {
        background-color: rgba(0, 0, 0, 0.5);
        position: absolute;
        width: 100%;
        height: 100%;
        top: 0;
        left: 0;
        display: none;
        align-items: center;
        justify-content: center;
        .icon {
          color: #fff;
        }
      }
      &:hover {
        .delete {
          display: flex;
        }
      }
    }
  }
  .uploader-icon {
    color: #aaaaaa;
    font-size: 22px;
    transition: all 0.3s;
  }
}
.count-style {
  display: inline-block;
  width: 45%;
  height: 60px;
}
.division-line {
  text-align: center;
  display: inline-block;
  color: #999;
  width: 50px;
}
.clock {
  display: inline-block;
}
.upload-style {
  vertical-align: middle;
  display: inline-block;
  // width: 60px;
  // height: 60px;
  border: none;
}
.img-style {
  margin: auto;
  background-color: #eee;
  width: 90px;
  height: 60px;
  vertical-align: middle;
}
.avatar {
  width: 60px;
  height: 60px;
  display: block;
}
.line-style {
  background-color: #dfe2e8;
  height: 1px;
  // width: 80%;
  // margin: 0 auto;
  margin-bottom: 20px;
}
</style>
admin/src/views/combo/components/Edit.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,229 @@
<template>
  <GlobalWindow :title="param.id ? '编辑套餐' : '新建套餐'" :visible.sync="isShowModal" :confirm-working="isLoading"
    width="1000px" @close="close" @confirm="confirm">
    <el-form :model="param" label-width="100px" ref="form" :rules="rules">
      <div class="form_title">基本信息</div>
      <el-form-item label="套餐名称" prop="name">
        <el-input class="w200" v-model="param.name" placeholder="请输入套餐名称" v-trim />
      </el-form-item>
      <el-form-item label="类型">
        <el-select class="w200" :disabled="true" v-model="param.warehouseId">
          <el-option label="期限卡" :value="0"></el-option>
        </el-select>
      </el-form-item>
      <el-form-item label="每日骑行限制">
        <div>
          <el-radio v-model="param.aa" label="1">不限制</el-radio>
          <el-radio v-model="param.aa" label="2">限制时长</el-radio>
        </div>
      </el-form-item>
      <el-form-item label="销售价">
        <el-input class="w200" v-model="param.name" placeholder="请输入价格" v-trim />
      </el-form-item>
      <el-form-item label="划线价">
        <el-input class="w200" v-model="param.name" placeholder="请输入展示的划线价" v-trim />
      </el-form-item>
      <el-form-item label="销售渠道">
        <el-checkbox v-model="param.ada">小程序端</el-checkbox>
      </el-form-item>
      <el-form-item label="套餐图片">
        <div class="df_ac">
          <UploadAvatarImage :file="{ 'imgurlfull': param.fileFullUrl, 'imgurl': param.fileUrl }"
            :uploadData="{ folder: 'ywPatrol/' }" @uploadSuccess="uploadAvatarSuccess" @uploadEnd="isUploading = false"
            @uploadBegin="isUploading = true" />
          <div class="img_place">
            <div>上传图片不允许涉及政治敏感与色情;</div>
            <div>图片格式必须为:png,PNG,jpeg,jpg,JPG;不可大于2M;建议使用</div>
            <div>ng格式图片,以保持最佳效果;建议图片尺寸为144px*144px</div>
          </div>
        </div>
      </el-form-item>
      <el-form-item label="套餐简介">
        <el-input class="w400" v-model="param.name" placeholder="请输入套餐简介" v-trim />
      </el-form-item>
      <el-form-item label="套餐描述">
        <RichEditor :content="{ content: param.content }" @edit="param.content = $event"></RichEditor>
      </el-form-item>
      <div class="form_title">
        <div>适用规则</div>
        <div class="placeholder9">销售时间、使用时间等设置</div>
      </div>
      <el-form-item label="销售时段">
        <el-date-picker class="w400" v-model="param.value1" value-format="yyyy-MM-dd" type="daterange" range-separator=" ~ " />
      </el-form-item>
      <div class="df_ac">
        <el-form-item label="使用时间" class="mr16">
          <el-select v-model="param.aaadd" style="width: 140px;">
            <el-option label="固定日期" :value="0"></el-option>
            <el-option label="购买后生效" :value="1"></el-option>
            <el-option label="指定日期生效" :value="1"></el-option>
          </el-select>
        </el-form-item>
        <!-- <el-form-item label-width="80px" label="固定日期">
          <el-date-picker v-model="param.value1" value-format="yyyy-MM-dd" type="daterange" range-separator=" ~ " />
        </el-form-item> -->
        <!-- <el-form-item label-width="60px" label="有效期">
          <el-input style="width: 130px;" v-model="param.name" placeholder="请输入有效天数" v-trim />
        </el-form-item> -->
        <el-form-item label-width="0px">
          <div class="df_ac">
            <el-date-picker class="w200" v-model="param.dasdas" value-format="yyyy-MM-dd" type="date" />
            <span class="ml10 mr10">开始生效,有效期</span>
            <el-input style="width: 130px;" v-model="param.name" placeholder="请输入有效天数" v-trim />
            <span class="ml10">天</span>
          </div>
        </el-form-item>
      </div>
      <el-form-item label="适用范围">
        <el-checkbox-group v-model="param.checkList">
          <el-checkbox label="工作日"></el-checkbox>
          <el-checkbox label="节假日"></el-checkbox>
        </el-checkbox-group>
      </el-form-item>
      <el-form-item label="适用项目">
        <el-checkbox-group v-model="param.checkList">
          <el-checkbox label="自行车"></el-checkbox>
          <el-checkbox label="电动车"></el-checkbox>
        </el-checkbox-group>
      </el-form-item>
      <el-form-item label="总限额">
        <el-input class="w400" v-model="param.name" placeholder="请输入总发售数量" v-trim />
        <div class="placeholder9">请输入总发售数量,销量大于该数量后,不再支持销售;为空表示不限制</div>
      </el-form-item>
      <el-form-item label="日限额">
        <el-input class="w400" v-model="param.name" placeholder="请输入单日发售数量" v-trim />
        <div class="placeholder9">请输入日发售数量,当日销量大于该数量后,不再支持销售;为空表示不限制</div>
      </el-form-item>
    </el-form>
    <!--  -->
  </GlobalWindow>
</template>
<script>
import GlobalWindow from '@/components/common/GlobalWindow'
// import { fetchList as getStoreList } from '@/api/ywWarehouse'
// import { ywOutinboundCreate } from '@/api/store/index'
import UploadAvatarImage from '@/components/common/UploadAvatarImage'
import { StoreTypeOps, rules } from './config'
import { Message } from 'element-ui'
import RichEditor from '@/components/common/RichEditor'
// import dayjs from 'dayjs'
export default {
  name: 'OperaCategoryWindow',
  components: { GlobalWindow, UploadAvatarImage, RichEditor },
  data() {
    return {
      // è¡¨å•数据
      param: { checkList: [], content: '' },
      isShowModal: false,
      isShowSel: false,
      isLoading: false,
      isUploading: false,
      // éªŒè¯è§„则
      rules,
      storeList: [],
      list: [],
      StoreTypeOps: [],
      dataList: [],
    }
  },
  created() {
    // this.initData()
  },
  methods: {
    confirm() {
      this.$refs['form'].validate((valid) => {
        if (valid) {
          const { param, list } = this
          if (list.length == 0) return Message.warning('请先选择物料信息')
          let count = 0 // å…¥åº“数量必填
          list.forEach(item => {
            if (!item.stock) count++
          })
          if (count > 0) return Message.warning('请输入正确的入库数量')
          this.isLoading = true
          ywOutinboundCreate({
            ...param,
            recordList: list
          }).then(res => {
            this.isLoading = false
            Message.success('提交成功')
            this.$emit('success')
            this.close()
          }, () => {
            this.isLoading = false
          })
        }
      })
    },
    initData() {
      this.$set(this.param, 'doneDate', dayjs().format('YYYY-MM-DD'))
      getStoreList({ capacity: 9999, page: 1, model: { status: 0 } }).then(res => {
        this.storeList = res.records || []
      })
    },
    changeSel(val) {
      const list = val
      list.forEach(item => {
        const index = this.list.findIndex(i => i.id == item.id)
        if (index == -1) {
          item.materialId = item.id
          item.multifile = null
          item.createDate = null
          this.list.push(item)
        }
      })
    },
    uploadAvatarSuccess(file) {
      this.$set(this.param, 'fileUrl', file.imgurl)
      this.$set(this.param, 'fileFullUrl', file.imgurlfull)
    },
    handleOpenMaterial() {
      this.isShowSel = true
      this.$nextTick(() => {
        this.$refs.AssetSelRef.isShowModal = true
        this.$refs.AssetSelRef.getList()
      })
    },
    close() {
      this.isShowModal = false
      this.$emit('close')
    },
    getDetail(id) {
      getInfoById(id).then(res => {
        this.param = res
      })
    },
  }
}
</script>
<style lang="scss" scoped>
@import "@/assets/style/variables.scss";
.form_title {
  display: flex;
  align-items: center;
  color: $primary-color;
  margin-bottom: 16px;
  .placeholder9 {
    color: #999999;
    font-size: 12px;
    margin-left: 12px;
  }
}
.img_place{
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  margin-left: 12px;
  color: #999999;
  font-size: 12px;
  padding: 8px 0;
}
</style>
admin/src/views/combo/components/OrderDetail.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,105 @@
<template>
  <GlobalWindow :title="title" :visible.sync="visible" :confirm-working="isWorking">
    <div class="title">支付明细</div>
    <el-table :data="list" stripe border>
      <el-table-column prop="id" label="订单编号" show-overflow-tooltip align="center"></el-table-column>
      <el-table-column prop="onlineorderId" label="交易单号" show-overflow-tooltip align="center"></el-table-column>
      <el-table-column prop="refundType" label="交易类型" width="100px" align="center">
        <template slot-scope="{row}">
          {{ typeToStr(row.refundType) }}
        </template>
      </el-table-column>
      <el-table-column prop="money" label="交易金额(元)" width="100px" align="center"></el-table-column>
      <el-table-column prop="payWay" label="渠道" width="100px" align="center">
        <template slot-scope="{row}">
          {{ row.payWay==0? '微信' : '支付宝' }}
        </template>
      </el-table-column>
      <el-table-column prop="payDate" label="交易时间" width="150px" align="center"></el-table-column>
    </el-table>
    <div class="title">骑行记录</div>
    <el-table
      :data="memberRidesList"
      stripe
      border
    >
      <el-table-column prop="openid" label="用户" width="250px" show-overflow-tooltip align="center"></el-table-column>
      <el-table-column prop="bikeCode" label="车辆编号" width="100px" align="center"></el-table-column>
      <el-table-column prop="bikeType" label="车类型" width="200px" align="center"></el-table-column>
      <el-table-column prop="rideTime" label="借出时长(分)" width="200px" align="center"></el-table-column>
      <el-table-column prop="duration" label="计费时长(分)" width="200px" align="center"></el-table-column>
      <el-table-column prop="bikeType" label="车类型" width="150px" align="center"></el-table-column>
      <el-table-column prop="rentDate" label="借出时间" width="150px" align="center"></el-table-column>
      <el-table-column prop="backDate" label="还车时间" width="150px" align="center"></el-table-column>
      <el-table-column prop="closeStatus" fixed="right" label="结算状态" width="100px" align="center">
        <template slot-scope="{row}">
          {{ row.closeStatus == 0 ? '未结算' : '已结算' }}
        </template>
      </el-table-column>
    </el-table>
    <div slot="footer">
      <el-button @click="visible=false">返回</el-button>
    </div>
  </GlobalWindow>
</template>
<script>
import BaseOpera from '@/components/base/BaseOpera'
import GlobalWindow from '@/components/common/GlobalWindow'
// import GoodsOrderList from './goodsOrderList.vue'
export default {
  name: 'OperaSitesWindow',
  extends: BaseOpera,
  components: { GlobalWindow },
  data () {
    return {
      // è¡¨å•数据
      form: {
        goodsorderId: ''
      },
      list: [],
      memberRidesList: [],
      // 0结算退款 1强制结算退款 2结算后退款 [99: è™šæ‹Ÿtype æ”¯ä»˜æŠ¼é‡‘]
      type: [
        { label: '结算退款', id: 0 },
        { label: '平台自动结算退款', id: 1 },
        { label: '强制结算退款', id: 2 },
        { label: '结算后退款', id: 3 },
        { label: '支付押金', id: 99 },
      ],
    }
  },
  created() {
  },
  methods: {
    open(title, target) {
      debugger
      this.title = title
      this.visible = true
      // æ–°å»º
      this.form = target
      this.$nextTick(() => {
        this.list = target.payOrderDTOList
        this.memberRidesList = target.memberRidesList
        // this.$refs.goodsOrderList.reload(target.model)
      })
    },
    typeToStr(type) {
      let temp = this.type.find(item => item.id == type )
      return temp ? temp.label : '-'
    }
  },
}
</script>
<style scoped>
.title {
  font-size: 18px;
  font-weight: 600;
  color: #333;
  margin-bottom: 20px;
  margin-top: 20px;
}
</style>
admin/src/views/combo/components/config.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,34 @@
export const pickerOptions = { // ç²¾ç¡®åˆ°ç§’
  disabledDate(time) {
    return time.getTime() < new Date(new Date().toLocaleDateString()).getTime()
  },
  shortcuts: [
    {
      text: '7天内失效',
      onClick(picker) {
        const end = new Date()
        const start = new Date()
        end.setTime(start.getTime() + 3600 * 1000 * 24 * 7)
        picker.$emit('pick', [start, end])
      }
    },
    {
      text: '30天内失效',
      onClick(picker) {
        const end = new Date()
        const start = new Date()
        end.setTime(start.getTime() + 3600 * 1000 * 24 * 30)
        picker.$emit('pick', [start, end])
      }
    },
    {
      text: '90天内失效',
      onClick(picker) {
        const end = new Date()
        const start = new Date()
        end.setTime(start.getTime() + 3600 * 1000 * 24 * 90)
        picker.$emit('pick', [start, end])
      }
    }
  ]
}
admin/src/views/combo/index.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,165 @@
<template>
  <div class="main_app">
    <QueryForm v-model="filters" :query-form-config="queryFormConfig" @handleQuery="getList(1)" @clear="clear" />
    <div class="table_btns">
      <el-button type="primary" @click="handleEdit()">新增</el-button>
    </div>
    <el-table v-loading="loading" :data="list" stripe border>
      <el-table-column prop="code" label="套餐名称" align="center" min-width="120" show-overflow-tooltip />
      <el-table-column prop="" label="套餐类型" align="center" min-width="100" show-overflow-tooltip />
      <el-table-column prop="" label="次数" align="center" min-width="100" show-overflow-tooltip />
      <el-table-column prop="" label="有效期" align="center" min-width="100" show-overflow-tooltip />
      <el-table-column prop="" label="ä»·æ ¼" align="center" min-width="100" show-overflow-tooltip />
      <el-table-column prop="" label="总发行数量" align="center" min-width="100" show-overflow-tooltip />
      <el-table-column prop="" label="已售售量" align="center" min-width="100" show-overflow-tooltip />
      <el-table-column prop="" label="销售渠道" align="center" min-width="100" show-overflow-tooltip />
      <el-table-column prop="" label="销售时段" align="center" min-width="100" show-overflow-tooltip />
      <el-table-column prop="" label="状态" align="center" min-width="100" show-overflow-tooltip />
      <el-table-column label="操作" fixed="right" align="center" min-width="80" show-overflow-tooltip>
        <template v-slot="{ row }">
          <span @click="handleDetail(row)" class="primaryColor pointer">查看详情</span>
        </template>
      </el-table-column>
    </el-table>
    <div class="table_btns">
      <Pagination @size-change="handleSizeChange" @current-change="getList" :pagination="pagination" />
    </div>
    <!--  -->
    <Edit v-if="isShowEdit" @close="isShowEdit = false" @success="getList" ref="EditRef" />
    <ComboDetail v-if="isShowDetail" ref="DetailRef" />
  </div>
</template>
<script>
import BasePageTemp from '@/components/base/BasePageTemp'
import TableLayout from '@/layouts/TableLayout'
import Edit from './components/Edit'
import ComboDetail from './components/ComboDetail.vue'
export default {
  extends: BasePageTemp,
  components: {
    TableLayout,
    Edit,
    ComboDetail
  },
  data() {
    return {
      loading: false,
      isShowEdit: false,
      isShowDetail: false,
      queryFormConfig: {
        formItems: [
          {
            filed: 'name',
            type: 'input',
            label: '套餐名称',
          },
          {
            filed: 'type',
            type: 'select',
            label: '适用项目',
            labelCode: 'name',
            valueCode: 'id',
            options: []
          },
          {
            filed: 'status',
            type: 'select',
            label: '状态',
            options: []
          },
        ],
        online: true
      },
      list: [{}]
    }
  },
  created() {
    // this.getList()
    // this.initData()
  },
  methods: {
    handleSub() {
      this.$refs.ruleForm.validate((valid) => {
        if (valid) {
          alert('submit!')
        }
      })
    },
    handleEdit() {
      this.isShowEdit = true
      this.$nextTick(() => {
        this.$refs.EditRef.isShowModal = true
      })
    },
    handleDetail(row) {
      this.isShowDetail = true
      this.$nextTick(() => {
        this.$refs.DetailRef.isShowModal = true
        // this.$refs.DetailRef.getDetail(row.id)
      })
    },
    handleEx() {
      this.$dialog.exportConfirm('确认导出吗?')
        .then(() => {
          this.loading = true
          ywOutinboundEx({
            page: this.pagination.page,
            capacity: 1000000,
            model: this.filters
          })
            .then(response => {
              this.download(response)
            })
            .catch(e => {
              this.$tip.apiFailed(e)
            })
            .finally(() => {
              this.loading = false
            })
        })
        .catch(() => { })
    },
    initData() {
      getStoreList({ capacity: 9999, page: 1, model: {} }).then(res => {
        this.queryFormConfig.formItems[1].options = res.records || []
      })
    },
    getList(page) {
      const { pagination, filters } = this
      this.loading = true
      if (page) { pagination.page = page }
      ywOutinboundPage({
        model: {
          ...filters,
          inOut: 0
        },
        // sorts: [{ direction: 'DESC', property: 'param1' }],
        capacity: pagination.pageSize,
        page: page,
      }).then(res => {
        this.loading = false
        this.list = res.records || []
        this.list.forEach(item => {
          item.typeName = this.StoreTypeOps[item.type].name
        })
        this.pagination.total = res.total || 0
      }, () => {
        this.loading = false
      })
    },
    clear() {
      this.filters = { inOut: 0 }
      this.pagination.pageSize = 10
      this.pagination.page = 1
      this.getList()
    },
    handleSizeChange(capacity) {
      this.pagination.pageSize = capacity
      this.getList()
    }
  }
}
</script>
<style></style>
admin/src/views/combo/order.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,156 @@
<template>
  <div class="main_app">
    <Breadcrumb />
    <QueryForm v-model="filters" :query-form-config="queryFormConfig" @handleQuery="getList(1)" @clear="clear" />
    <div class="table_btns">
      <el-button type="primary" @click="handleEx()">导出</el-button>
    </div>
    <el-table v-loading="loading" :data="list" stripe border>
      <el-table-column prop="code" align="center" label="订单编号" min-width="140" show-overflow-tooltip>
        <template scope="{row}">
          <span class="primaryColor pointer">{{ row.orderId }}</span>
        </template>
      </el-table-column>
      <el-table-column prop="" align="center" label="套餐卡" min-width="120" show-overflow-tooltip />
      <el-table-column prop="" align="center" label="合计(元)" min-width="80" show-overflow-tooltip />
      <el-table-column prop="" align="center" label="实付(元)" min-width="80" show-overflow-tooltip />
      <el-table-column prop="" align="center" label="已退金额(元)" min-width="100" show-overflow-tooltip />
      <el-table-column prop="" align="center" label="用户信息" min-width="120" show-overflow-tooltip />
      <el-table-column prop="" align="center" label="订单状态" min-width="110" show-overflow-tooltip />
      <el-table-column label="操作" fixed="right" align="center" min-width="80" show-overflow-tooltip>
        <template v-slot="{ row }">
          <span @click="handleDetail(row.id)" v-permissions="['business:ywoutinboundrecord:query']"
            class="primaryColor pointer">查看详情</span>
        </template>
      </el-table-column>
    </el-table>
    <div class="table_btns">
      <Pagination @size-change="handleSizeChange" @current-change="getList" :pagination="pagination" />
    </div>
    <!--  -->
    <OrderDetail v-if="isShowDetail" ref="OrderDetailRef" />
  </div>
</template>
<script>
import BasePageTemp from '@/components/base/BasePageTemp'
import Breadcrumb from '@/layouts/Breadcrumb'
import OrderDetail from './components/OrderDetail.vue'
export default {
  extends: BasePageTemp,
  components: {
    Breadcrumb,
    OrderDetail
  },
  data() {
    return {
      loading: false,
      isShowDetail: false,
      queryFormConfig: {
        formItems: [
          {
            filed: 'orderId',
            type: 'input',
            label: '订单编号',
          },
          {
            filed: 'name',
            type: 'input',
            label: '套餐卡',
            placeholder: '请输入卡名称',
          },
          {
            filed: 'pay',
            type: 'select',
            label: '支付方式',
            options: []
          },
          {
            filed: 'status',
            type: 'select',
            label: '订单状态',
            options: []
          },
          {
            filed: 'time',
            type: 'date',
            label: '支付时间',
          },
          {
            filed: 'username',
            type: 'input',
            label: '用户信息',
          },
        ],
        online: true
      }
    }
  },
  created() {
    // this.getList()
    // this.initData()
  },
  methods: {
    handleDetail(id) {
      getDetail(id)
        .then(res => {
          this.$refs.OrderDetailRef.open('订单详情', res)
        })
        .catch(err => {
          this.$tip.apiFailed(err)
        })
    },
    handleEx() {
      this.$dialog.exportConfirm('确认导出吗?')
        .then(() => {
          this.loading = true
          ywOutinboundEx({
            page: this.pagination.page,
            capacity: 1000000,
            model: this.filters
          })
            .then(response => {
              this.download(response)
            })
            .catch(e => {
              this.$tip.apiFailed(e)
            })
            .finally(() => {
              this.loading = false
            })
        })
        .catch(() => { })
    },
    initData() {
      getStoreList({ capacity: 9999, page: 1, model: {} }).then(res => {
        this.queryFormConfig.formItems[1].options = res.records || []
      })
    },
    getList(page) {
      const { pagination, filters } = this
      this.loading = true
      if (page) { pagination.page = page }
      ywOutinboundPage({
        model: {
          ...filters,
          inOut: 0
        },
        // sorts: [{ direction: 'DESC', property: 'param1' }],
        capacity: pagination.pageSize,
        page: page,
      }).then(res => {
        this.loading = false
        this.list = res.records || []
        this.list.forEach(item => {
          item.typeName = this.StoreTypeOps[item.type].name
        })
        this.pagination.total = res.total || 0
      }, () => {
        this.loading = false
      })
    },
  }
}
</script>
<style></style>
admin/src/views/combo/record.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,494 @@
<template>
  <div class="main_app">
    <Breadcrumb />
    <QueryForm v-model="querys" :query-form-config="queryFormConfig" @handleQuery="getList(1)" @clear="clearQueryForm">
      <template #btns>
        <el-button v-if="meta.indexOf('MealsUseDetailExport') > -1" type="primary"
          @click="comboRecordExport">导出</el-button>
      </template>
      <template #indate>
        <el-date-picker v-model="querys.indate" type="datetimerange" range-separator="至" start-placeholder="开始日期"
          end-placeholder="结束日期" format="yyyy-MM-dd HH:mm:ss" value-format="yyyy-MM-dd HH:mm:ss" class="w400"
          :picker-options="pickerOptions" />
      </template>
    </QueryForm>
    <div class="table_btns">
      <el-button v-preventReClick plain type="primary" @click="handleEx">导出</el-button>
      <el-button v-preventReClick plain type="danger" @click="openModal('zuofei')">作废</el-button>
      <el-button v-preventReClick plain @click="openModal('tiaozheng')">套餐调整</el-button>
    </div>
    <el-table v-loading="loading" :data="list" stripe border @selection-change="handleSelectionChange">
      <el-table-column fixed="left" align="center" type="selection" :selectable="handleDisable" width="55" />
      <el-table-column align="center" label="套餐票号" width="300" show-overflow-tooltip>
        <template v-slot="scope">
          <span class="primaryColor pointer" @click="comboDetail(scope.row)">{{
            scope.row.id
            }}</span>
        </template>
      </el-table-column>
      <el-table-column align="center" label="套餐类型" width="120">
        <template v-slot="scope">
          <span v-if="scope.row.mealsType === '0'">门票次卡</span>
          <span v-if="scope.row.mealsType === '1'">门票期限卡</span>
          <span v-if="scope.row.mealsType === '2'">预定次卡</span>
          <span v-if="scope.row.mealsType === '3'">课程预约次卡</span>
          <span v-if="scope.row.mealsType === '4'">课程期限卡</span>
        </template>
      </el-table-column>
      <el-table-column align="center" label="套餐名称" show-overflow-tooltip width="160" prop="mealsName" />
      <el-table-column align="center" label="用户信息" min-width="240" prop="memberInfo" show-overflow-tooltip />
      <el-table-column align="center" label="使用次数" width="80" prop="useCount">
        <template v-slot="scope">
          <span v-if="scope.row.mealsType === '1'">-</span>
          <span v-else>{{ scope.row.useCount }}</span>
        </template>
      </el-table-column>
      <el-table-column align="center" label="有效日期" width="80" prop="remainCount">
        <template v-slot="scope">
          <span v-if="scope.row.mealsType === '1'">-</span>
          <span v-else>{{ scope.row.remainCount }}</span>
        </template>
      </el-table-column>
      <el-table-column fixed="right" align="center" label="套餐状态" width="80">
        <template v-slot="scope">
          <span v-if="scope.row.status === '0'" class="text_success">正常</span>
          <span v-if="scope.row.status === '1'" class="text_warning">冻结</span>
          <span v-if="scope.row.status === '2'" class="text-danger">作废</span>
          <span v-if="scope.row.status === '3'" class="text-danger">失效</span>
        </template>
      </el-table-column>
      <el-table-column align="center" label="有效日期" width="120" prop="validTime" />
      <el-table-column align="center" label="操作" fixed="right" width="150">
        <template v-slot="scope">
          <template>
            <el-button v-if="
              meta.indexOf('MealsMemberPartRefund') > -1 &&
              (scope.row.status == '0' || scope.row.status == '1')
            " type="text" @click="rowClickRefund(scope.row)">退款</el-button>
            <el-button v-if="scope.row.status == '0'" type="text"
              @click="getServiceChargePriceBtn('2', scope.row.id)">冻结</el-button>
          </template>
        </template>
      </el-table-column>
    </el-table>
    <div class="table_btns">
      <Pagination @size-change="handleSizeChange" @current-change="getList" :pagination="pagination" />
    </div>
    <el-dialog title="套餐调整" :visible.sync="isShowAdjust" width="500px">
      <div class="adjust_modal">
        <div style="margin-top: -30px; margin-bottom: 10px;">
          <el-radio v-model="adjustData.aa" label="1">已选当前2条数据</el-radio>
        </div>
        <div style="margin-bottom: 16px;">
          <el-radio v-model="adjustData.aa" label="1">已选现有筛选条件下全部的11条数据</el-radio>
        </div>
        <div class="df_ac mb5">
          <span class="key">有效期增加:</span>
          <el-input v-model="adjustData.addTime" oninput="value=value.replace(/[^\d]/g,'')" class="flex1 mr10" />
          <span>天</span>
        </div>
        <div class="df_ac mb20">
          <span class="key" />
          <span class="text_warning">修改后套餐有效期增加以上天数</span>
        </div>
        <div class="df_ac mt20">
          <span class="key">调整备注:</span>
          <el-input v-model="ModelRemark" style="width: 356px" placeholder="请按要求输入备注说明,非必填" />
        </div>
      </div>
      <span slot="footer" class="dialog-footer">
        <el-button @click="isShowAdjust = false">取消</el-button>
        <el-button v-preventReClick type="primary" :loading="subLoading" @click="handleModelEnter">确定</el-button>
      </span>
    </el-dialog>
    <Refund v-if="isShowRefund" ref="RefundRef" @close="isShowRefund = false" @success="refundSuccess" />
    <Detail v-if="isShowDetail" ref="detailRef" />
    <orderDialog ref="child" @orderSuccess="getList()" />
  </div>
</template>
<script>
import { pickerOptions } from './components/config'
import BasePageTemp from '@/components/base/BasePageTemp'
import Breadcrumb from '@/layouts/Breadcrumb'
// import Detail from '../comboDetail'
// import Refund from './refund.vue'
export default {
  name: 'SalesRecord',
  extends: BasePageTemp,
  components: { Breadcrumb },
  data() {
    return {
      exportLoading: false,
      isShowDetail: false,
      isShowRefund: false,
      queryFormConfig: {
        formItems: [{
          filed: 'id',
          type: 'input',
          label: '套餐票号',
          placeholder: '请输入套餐号',
          clearable: true
        }, {
          filed: 'mealsName',
          type: 'input',
          label: '套餐名称',
          placeholder: '请输入套餐名称',
          clearable: true
        }, {
          filed: 'memberSearchValue',
          type: 'input',
          label: '用户信息',
          clearable: true
        }, {
          filed: 'status',
          type: 'select',
          label: '状态',
          placeholder: '请选择状态',
          clearable: true,
          options: [
            { value: '0', label: '正常' },
            { value: '1', label: '冻结' },
            { value: '2', label: '作废' },
            { value: '3', label: '失效' }]
        }],
        online: true
      },
      pickerOptions,
      querys: {
        id: '',
        mealsName: '',
        memberSearchValue: '',
        status: '',
        indate: []
      },
      saleRecordList: [],
      saleRecordTotal: 0,
      selectSalesList: [],
      saleRecordLoading: false,
      subLoading: false,
      isShowModal: false,
      ModalTitle: '',
      ModalText: '',
      ModelRemark: '',
      // â¬‡ï¸adjust调整相关
      isShowAdjust: false,
      adjustData: {
        addNum: '',
        addTime: ''
      },
      serviceChargePrice: '',
      serviceChargeId: ''
    }
  },
  created() {
    // this.meta = this.$route.meta.buttons || []
    // this.getList(1)
  },
  methods: {
    rowClickRefund(row) {
      this.isShowRefund = true
      this.$nextTick(() => {
        this.$refs.RefundRef.getPrice(row)
        this.$refs.RefundRef.isShow = true
      })
    },
    refundSuccess() {
      this.isShowRefund = false
      this.getList()
    },
    getServiceChargePriceBtn(type, mealsMemberId) {
      this.serviceChargeId = mealsMemberId
      getServiceChargePrice({
        param: {
          type,
          mealsMemberId
        }
      }).then((res) => {
        if (res.errorCode === '000000') {
          this.serviceChargePrice = res.record.price
          this.openModal('dongjie')
        }
      })
        .catch(() => { })
    },
    handleEx() {
      const { querys } = this
      this.exportLoading = true
      recordExport({
        param: {
          ...querys
        }
      }).then((res) => {
        this.exportLoading = false
        if (res.errorCode === '000000') {
          const a = document.createElement('a') // åˆ›å»ºä¸€ä¸ªa标签元素
          a.style.display = 'none' // è®¾ç½®å…ƒç´ ä¸å¯è§
          a.href = res.record.showUrl // è®¾ç½®ä¸‹è½½åœ°å€
          document.body.appendChild(a) // åŠ å…¥
          a.click() // è§¦å‘点击,下载
          document.body.removeChild(a) //
          this.$message.success('导出成功')
        }
      })
        .catch(() => {
          this.exportLoading = false
        })
    },
    handleDisable(row, index) {
      if (row.status === '2') {
        return false
      } else {
        return true
      }
    },
    // æŸ¥è¯¢è¡¨æ ¼æ•°æ®
    getList(page) {
      const { querys, pagination } = this
      if (page) {
        pagination.page = page
        this.pagination.page = Number(page)
      }
      if (querys.indate && querys.indate.length > 0) {
        querys.startTime = querys.indate[0]
        querys.endTime = querys.indate[1]
      } else {
        querys.startTime = null
        querys.endTime = null
      }
      pagination.firstQueryTime = parseTime(new Date())
      this.saleRecordLoading = true
      comboSalesRecordPost({
        pagination, param: {
          ...querys,
          venueId: sessionStorage.getItem('venueId')
        }
      }).then(res => {
        this.saleRecordLoading = false
        if (res.errorCode === '000000') {
          this.saleRecordLoading = false
          this.saleRecordTotal = res.totalCount
          this.saleRecordList = res.recordList
          if (res.totalCount && res.recordList.length === 0 && pagination.page > 1) {
            this.getList(Math.ceil(res.totalCount / pagination.rows))
          }
        }
      }).catch(() => {
        this.saleRecordLoading = false
      })
    },
    clearQueryForm() {
      // eslint-disable-next-line no-unused-vars
      this.querys = {}
      this.getList(1)
    },
    // æ‰“å¼€modal å†»ç»“ è§£å†» ä½œåºŸ
    openModal(type) {
      const { selectSalesList } = this
      this.ModelRemark = ''
      this.adjustData.addNum = ''
      this.adjustData.addTime = ''
      switch (type) {
        case 'dongjie':
          this.ModalTitle = '套餐冻结'
          this.ModalText = '确定冻结选中套餐吗?冻结后,套餐将无法使用'
          break
        case 'jiedong':
          this.ModalTitle = '套餐解冻'
          this.ModalText = '确定解冻选中套餐吗?解冻后,套餐可立即生效使用'
          break
        case 'zuofei':
          this.ModalTitle = '套餐作废'
          this.ModalText = '确定作废选中套餐吗?作废后,套餐不可使用'
          break
        case 'tiaozheng':
          this.ModalTitle = '套餐调整'
          break
        default:
          break
      }
      if (selectSalesList.length === 0 && type !== 'dongjie') {
        return this.$message.warning(`请先选择要${this.ModalTitle.slice(2)}的套餐`)
      }
      if (this.ModalTitle === '套餐调整') {
        this.isShowAdjust = true
      } else {
        this.isShowModal = true
      }
    },
    // ç¡®å®š å†»ç»“ è§£å†» ä½œåºŸ
    handleModelEnter() {
      // if (!this.ModelRemark) {
      //   this.$message.warning('操作备注必填')
      //   return
      // }
      switch (this.ModalTitle) {
        case '套餐冻结':
          this.Freeze()
          break
        case '套餐解冻':
          this.Unfreeze()
          break
        case '套餐作废':
          this.cancellation()
          break
        case '套餐调整':
          this.handleAdjust()
          break
        default:
          break
      }
    },
    // å†»ç»“
    Freeze() {
      const that = this
      const data = {
        type: '1',
        handleRemake: this.ModelRemark,
        isCreateOrder: '1',
        id: this.serviceChargeId
      }
      this.subLoading = true
      handleComboSalesPost({ param: { ...data } }).then(res => {
        this.subLoading = false
        this.isShowModal = false
        if (res.errorCode === '000000') {
          const obj = res.record
          if (obj && obj.price) {
            obj.goodsInfos = obj.serviceChargeOrderInfo
            obj.allPrice = obj.price
            this.$refs.child.continuePay(obj, 'handlingFees')
          } else {
            this.$message.success('冻结成功')
            this.getList()
          }
          //
        } else if (res.errorCode === '200001') {
          this.$confirm('存在未处理订单, æ˜¯å¦è·³è½¬?', '提示', {
            confirmButtonText: '确定',
            cancelButtonText: '取消',
            type: 'warning',
            callback: () => { },
            beforeClose: (action, ctx, close) => {
              if (action !== 'confirm') {
                close()
                return
              }
              ctx.confirmButtonLoading = true
              that.$router.push({ name: 'HandlingFees' })
            }
          }).finally(() => {
            this.subLoading = false
            this.isShowModal = false
          })
        }
      })
    },
    // è§£å†»
    async Unfreeze() {
      const data = {
        type: '2',
        handleRemake: this.ModelRemark,
        id: this.selectSalesList.map(i => i.id).join(',')
      }
      this.subLoading = true
      const res = await handleComboSalesPost({ param: { ...data } }).catch(() => {
        this.subLoading = false
        this.isShowModal = false
      })
      this.subLoading = false
      this.isShowModal = false
      if (res && res.errorCode === '000000') {
        this.$message.success('解冻成功')
        this.getList()
      }
    },
    // è°ƒæ•´
    async handleAdjust() {
      if (!this.adjustData.addNum && !this.adjustData.addTime) {
        return this.$message.warning('请输入要调整的有效期天数或者余量次数')
      }
      const data = {
        type: '3',
        handleRemake: this.ModelRemark,
        addNum: this.adjustData.addNum || 0,
        addTime: this.adjustData.addTime || 0,
        id: this.selectSalesList.map(i => i.id).join(',')
      }
      this.subLoading = true
      const res = await handleComboSalesPost({ param: { ...data } }).catch(() => {
        this.subLoading = false
        this.isShowModal = false
      })
      this.subLoading = false
      this.isShowModal = false
      if (res && res.errorCode === '000000') {
        this.$message.success('套餐调整成功')
        this.getList()
        this.isShowAdjust = false
      }
    },
    // ä½œåºŸ
    async cancellation() {
      const data = {
        type: '4',
        handleRemake: this.ModelRemark,
        id: this.selectSalesList.map(i => i.id).join(',')
      }
      this.subLoading = true
      const res = await handleComboSalesPost({ param: { ...data } }).catch(() => {
        this.subLoading = false
        this.isShowModal = false
      })
      this.subLoading = false
      this.isShowModal = false
      if (res && res.errorCode === '000000') {
        this.$message.success('作废成功')
        this.getList()
      }
    },
    handleSelectionChange(val) {
      this.selectSalesList = val
    },
    comboDetail(item) {
      this.isShowDetail = true
      this.$nextTick(() => {
        this.$refs.detailRef.isShowModal = true
        this.$refs.detailRef.comboDetail(item)
      })
      // this.$router.push({
      //   name: 'comboDetail',
      //   query: item
      // })
    },
    pageSizeChange(val) {
      this.pagination.rows = val
      this.getList(1)
    }
  }
}
</script>
<style lang="scss" scoped>
.adjust_modal {
  .df_ac {
    .key {
      width: 92px;
      text-align: right;
    }
  }
  .el-dialog__body{
  }
  .text_warning {
    color: #e89e42;
  }
}
</style>
admin/src/views/operation/components/Map.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,73 @@
<template>
  <GlobalWindow title="绘制地图停车区域" :visible.sync="isShowModal" :confirm-working="isWorking" @confirm="confirm"
    width="1000px">
    <div class="map_title">站点名称 åœè½¦åŒºåŸŸç»˜åˆ¶</div>
    <div id="mapContainer" style="width: 100%; height: calc( 100% - 40px )"></div>
  </GlobalWindow>
</template>
<script>
import GlobalWindow from '@/components/common/GlobalWindow'
export default {
  components: {
    GlobalWindow
  },
  data() {
    return {
      isShowModal: false,
      isWorking: false,
    }
  },
  mounted() {
    this.$nextTick(() => {
      this.initMap()
    })
  },
  methods: {
    initMap() {
      this.map = new TMap.Map(document.getElementById("mapContainer"), {
        zoom: 14, // è®¾ç½®åœ°å›¾ç¼©æ”¾çº§åˆ«
        center: new TMap.LatLng(30.656964, 104.066186), // è®¾ç½®åœ°å›¾ä¸­å¿ƒç‚¹åæ ‡
      })
      var polygon = new TMap.MultiPolygon({
        map: this.map,
      })
      this.editor = new TMap.tools.GeometryEditor({
        // TMap.tools.GeometryEditor æ–‡æ¡£åœ°å€ï¼šhttps://lbs.qq.com/webApi/javascriptGL/glDoc/glDocEditor
        map: this.map, // ç¼–辑器绑定的地图对象
        overlayList: [
          // å¯ç¼–辑图层 æ–‡æ¡£åœ°å€ï¼šhttps://lbs.qq.com/webApi/javascriptGL/glDoc/glDocEditor#4
          {
            overlay: polygon,
            id: "polygon",
          },
        ],
        actionMode: TMap.tools.constants.EDITOR_ACTION.DRAW, // ç¼–辑器的工作模式
        activeOverlayId: this.activeId, // æ¿€æ´»å›¾å±‚
        snappable: true, // å¼€å¯å¸é™„
      })
      // ç›‘听绘制结束事件,获取绘制几何图形
      this.editor.on("draw_complete", (geometry) => {
        console.log('所有顶点坐标集合', geometry)
        // å¤šè¾¹å½¢å¤„理
        if (this.activeId === "polygon") {
          console.log("得到顶点经纬度的数组", geometry.paths)
        }
      })
    },
    confirm() { }
  }
}
</script>
<style lang="scss" scoped>
.map_title {
  font-size: 16px;
  font-weight: 500;
  margin-bottom: 10px;
}
#mapContainer {
}
</style>
admin/src/views/operation/components/SitesWindow.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,90 @@
<template>
  <GlobalWindow
    :title="title"
    :visible.sync="visible"
    :confirm-working="isWorking"
    @confirm="confirm"
    width="600px"
  >
    <el-form :model="form" ref="form" :rules="rules" label-width="100px">
      <el-form-item label="站点编号" prop="code">
        <el-input v-model="form.code" :disabled="form.id" placeholder="请输入站点编号,全局唯一" v-trim/>
      </el-form-item>
      <el-form-item label="站点名称" prop="name">
        <el-input v-model="form.name" placeholder="请输入站点名称" v-trim/>
      </el-form-item>
      <el-form-item label="是否异常上报" prop="needNotice">
        <el-radio-group v-model="form.needNotice">
          <el-radio :label="0">上报</el-radio>
          <el-radio :label="1">不上报</el-radio>
        </el-radio-group>
      </el-form-item>
      <!-- <el-form-item label="站点ip" prop="ip">
        <el-input v-model="form.ip" placeholder="请输入站点ip地址" v-trim/>
      </el-form-item>
      <el-form-item label="站点端口号" prop="port">
        <el-input v-model="form.port" placeholder="请输入站点端口号" v-trim/>
      </el-form-item> -->
      <!-- <el-form-item label="备注" prop="info">
        <el-input v-model="form.info" placeholder="请输入备注" v-trim/>
      </el-form-item> -->
    </el-form>
  </GlobalWindow>
</template>
<script>
import BaseOpera from '@/components/base/BaseOpera'
import GlobalWindow from '@/components/common/GlobalWindow'
export default {
  name: 'OperaSitesWindow',
  extends: BaseOpera,
  components: { GlobalWindow },
  data () {
    return {
      // è¡¨å•数据
      form: {
        id: null,
        name: '',
        code: '',
        needNotice:0,
        ip: '',
        port: ''
        // createDate: '',
        // creator: '',
        // editDate: '',
        // editor: '',
        // isdeleted: '',
        // info: '',
        // name: '',
        // code: '',
        // status: '',
        // lockNum: '',
      },
      // éªŒè¯è§„则
      rules: {
        code: [
          { required: true, message: '请输入站点编号', tigger: 'blur' },
        ],
        name: [
          { required: true, message: '请输入站点名称', tigger: 'blur' },
        ],
        ip: [
          { required: true, message: '请输入站点ip地址', tigger: 'blur' },
        ],
        port: [
          { required: true, message: '请输入站点端口号', tigger: 'blur' },
        ],
      }
    }
  },
  created () {
    this.config({
      api: '/business/sites',
      'field.id': 'id'
    })
  }
}
</script>
admin/src/views/operation/components/TramEdit.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,69 @@
<template>
  <GlobalWindow
    :title="title"
    :visible.sync="visible"
    :confirm-working="isWorking"
    @confirm="confirm"
    width="600px"
  >
    <el-form :model="form" ref="form" :rules="rules" label-width="100px">
      <el-form-item label="车辆类型" prop="code">
        <el-select  v-model="form.named" placeholder="请选择">
          <el-option label="3人电动车" :value="0"></el-option>
          <el-option label="4人电动车" :value="1"></el-option>
        </el-select>
      </el-form-item>
      <el-form-item label="车辆编号" prop="code">
        <el-input v-model="form.name" placeholder="请输入车辆编号" v-trim/>
      </el-form-item>
      <el-form-item label="控制器SN" prop="needNotice">
        <el-input v-model="form.name" placeholder="请输入控制器SN" v-trim/>
      </el-form-item>
    </el-form>
  </GlobalWindow>
</template>
<script>
import BaseOpera from '@/components/base/BaseOpera'
import GlobalWindow from '@/components/common/GlobalWindow'
export default {
  name: 'OperaSitesWindow',
  extends: BaseOpera,
  components: { GlobalWindow },
  data () {
    return {
      // è¡¨å•数据
      form: {
        id: null,
        name: '',
        code: '',
        needNotice:0,
        ip: '',
        port: ''
      },
      // éªŒè¯è§„则
      rules: {
        code: [
          { required: true, message: '请输入站点编号', tigger: 'blur' },
        ],
        name: [
          { required: true, message: '请输入站点名称', tigger: 'blur' },
        ],
        ip: [
          { required: true, message: '请输入站点ip地址', tigger: 'blur' },
        ],
        port: [
          { required: true, message: '请输入站点端口号', tigger: 'blur' },
        ],
      }
    }
  },
  created () {
    this.config({
      api: '/business/sites',
      'field.id': 'id'
    })
  }
}
</script>
admin/src/views/operation/site.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,109 @@
<template>
  <TableLayout :permissions="['business:sites:query']">
    <!-- æœç´¢è¡¨å• -->
    <el-form ref="searchForm" slot="search-form" :model="searchForm" label-width="100px" inline>
      <el-form-item label="站点编号" prop="code">
        <el-input v-model="searchForm.code" placeholder="请输入站点编号" @keypress.enter.native="search"></el-input>
      </el-form-item>
      <el-form-item label="站点名称" prop="name">
        <el-input v-model="searchForm.name" placeholder="请输入站点名称" @keypress.enter.native="search"></el-input>
      </el-form-item>
      <section>
        <el-button type="primary" @click="search">搜索</el-button>
        <el-button @click="reset">重置</el-button>
      </section>
    </el-form>
    <!-- è¡¨æ ¼å’Œåˆ†é¡µ -->
    <template v-slot:table-wrap>
      <ul class="toolbar" v-permissions="['business:sites:create']">
        <li><el-button type="primary" @click="$refs.operaSitesWindow.open('新建站点')" icon="el-icon-plus" v-permissions="['business:sites:create']">新建</el-button></li>
      </ul>
      <el-table
        v-loading="isWorking.search"
        :data="tableData.list"
        stripe
        border
      >
        <el-table-column prop="code" label="站点编号"  :sort-method="(a,b)=>{ return   a.code-b.code}"  sortable min-width="100px" align="center"></el-table-column>
        <el-table-column prop="name" label="站点名称" sortable min-width="100px" align="center"></el-table-column>
        <el-table-column prop="createTime" label="创建时间" sortable  min-width="100px" align="center"></el-table-column>
        <el-table-column
          v-if="containPermissions(['business:sites:update', 'business:sites:delete'])"
          label="操作"
          min-width="120"
          align="center"
          fixed="right"
        >
          <template slot-scope="{row}">
            <el-button type="text" @click="handleDraw(row)">绘制地图区域</el-button>
            <el-button type="text" @click="$refs.operaSitesWindow.open('编辑站点', row)" icon="el-icon-edit" v-permissions="['business:sites:update']">编辑</el-button>
            <el-button type="text" @click="deleteById(row)" icon="el-icon-delete" v-permissions="['business:sites:delete']">删除</el-button>
          </template>
        </el-table-column>
      </el-table>
      <pagination
        @size-change="handleSizeChange"
        @current-change="handlePageChange"
        :pagination="tableData.pagination"
      >
      </pagination>
    </template>
    <!-- æ–°å»º/修改 -->
    <OperaSitesWindow ref="operaSitesWindow" @success="handlePageChange" />
    <!--  æŸ¥çœ‹äºŒç»´ç   -->
    <AMap v-if="isShowMap" ref="MapRef" />
  </TableLayout>
</template>
<script>
import BaseTable from '@/components/base/BaseTable'
import TableLayout from '@/layouts/TableLayout'
import Pagination from '@/components/common/Pagination'
import OperaSitesWindow from './components/SitesWindow'
import AMap from './components/Map.vue'
export default {
  name: 'Sites',
  extends: BaseTable,
  components: { TableLayout, Pagination, OperaSitesWindow, AMap },
  data () {
    return {
      // æœç´¢
      searchForm: {
        id: '',
        createDate: '',
        creator: '',
        editDate: '',
        editor: '',
        isdeleted: '',
        info: '',
        name: '',
        code: '',
        status: '',
        lockNum: '',
        ip: '',
        clientVersion: ''
      },
      isShowMap: false
    }
  },
  created () {
    this.config({
      module: '站点信息表',
      api: '/business/sites',
      'field.id': 'id',
      'field.main': 'id'
    })
    this.search()
  },
  methods: {
    handleDraw() {
      this.isShowMap = true
      this.$nextTick(() => {
        this.$refs.MapRef.isShowModal = true
      })
    }
  }
}
</script>
admin/src/views/operation/tram.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,109 @@
<template>
  <TableLayout :permissions="['business:sites:query']">
    <!-- æœç´¢è¡¨å• -->
    <el-form ref="searchForm" slot="search-form" :model="searchForm" label-width="100px" inline>
      <el-form-item label="车辆编号" prop="code">
        <el-input v-model="searchForm.code" placeholder="请输入车辆编号" @keypress.enter.native="search"></el-input>
      </el-form-item>
      <el-form-item label="所在站点" prop="name">
        <el-input v-model="searchForm.name" placeholder="请输入名称/编码" @keypress.enter.native="search"></el-input>
      </el-form-item>
      <el-form-item label="电量情况" prop="name">
        <el-select v-model="searchForm.status" placeholder="电量情况" @change="search">
          <el-option label="正常" value="0" />
          <el-option label="电量低" value="1" />
        </el-select>
      </el-form-item>
      <section>
        <el-button type="primary" @click="search">搜索</el-button>
        <el-button @click="reset">重置</el-button>
      </section>
    </el-form>
    <!-- è¡¨æ ¼å’Œåˆ†é¡µ -->
    <template v-slot:table-wrap>
      <ul class="toolbar" v-permissions="['business:sites:create']">
        <li><el-button type="primary" @click="$refs.TramEditRef.open('新增车辆')" icon="el-icon-plus" v-permissions="['business:sites:create']">新建</el-button></li>
      </ul>
      <el-table
        v-loading="isWorking.search"
        :data="tableData.list"
        stripe
        border
      >
        <el-table-column prop="code" label="车辆编码"  :sort-method="(a,b)=>{ return   a.code-b.code}"  sortable min-width="100px" align="center"></el-table-column>
        <el-table-column prop="name" label="车辆类型" sortable min-width="100px" align="center"></el-table-column>
        <el-table-column prop="name" label="控制器SN" sortable min-width="100px" align="center"></el-table-column>
        <el-table-column prop="name" label="当前电压值" sortable min-width="100px" align="center"></el-table-column>
        <el-table-column prop="name" label="电量情况" sortable min-width="100px" align="center"></el-table-column>
        <el-table-column prop="name" label="站点编号" sortable min-width="100px" align="center"></el-table-column>
        <el-table-column prop="name" label="站点名称" sortable min-width="100px" align="center"></el-table-column>
        <el-table-column prop="createTime" label="最后通讯时间" sortable  min-width="100px" align="center"></el-table-column>
        <el-table-column
          v-if="containPermissions(['business:sites:update', 'business:sites:delete'])"
          label="操作"
          min-width="160"
          align="center"
          fixed="right"
        >
          <template slot-scope="{row}">
            <el-button type="text" @click="$refs.QRcode.open('查看二维码', row.code)" icon="el-icon-picture-outline-round">查看二维码</el-button>
            <el-button type="text" @click="$refs.TramEditRef.open('编辑车辆', row)" icon="el-icon-edit" v-permissions="['business:sites:update']">编辑</el-button>
            <el-button type="text" @click="deleteById(row)" icon="el-icon-delete" v-permissions="['business:sites:delete']">删除</el-button>
          </template>
        </el-table-column>
      </el-table>
      <pagination
        @size-change="handleSizeChange"
        @current-change="handlePageChange"
        :pagination="tableData.pagination"
      >
      </pagination>
    </template>
    <!-- æ–°å»º/修改 -->
    <TramEdit ref="TramEditRef" @success="handlePageChange"/>
    <!--  æŸ¥çœ‹äºŒç»´ç   -->
    <QRcode ref="QRcode" />
  </TableLayout>
</template>
<script>
import BaseTable from '@/components/base/BaseTable'
import TableLayout from '@/layouts/TableLayout'
import Pagination from '@/components/common/Pagination'
import TramEdit from './components/TramEdit.vue'
import QRcode from '@/components/business/QRcode'
export default {
  name: 'Sites',
  extends: BaseTable,
  components: { TableLayout, Pagination, TramEdit, QRcode },
  data () {
    return {
      // æœç´¢
      searchForm: {
        id: '',
        createDate: '',
        creator: '',
        editDate: '',
        editor: '',
        isdeleted: '',
        info: '',
        name: '',
        code: '',
        status: '',
        lockNum: '',
        ip: '',
        clientVersion: ''
      }
    }
  },
  created () {
    this.config({
      module: '站点信息表',
      api: '/business/sites',
      'field.id': 'id',
      'field.main': 'id'
    })
    this.search()
  }
}
</script>
admin/yarn.lock
ÎļþÒÑɾ³ý