Browse Source

Merge branch 'develop/3.0.6' into test

DESKTOP-2S67K1S\31396 2 years atrás
parent
commit
e25fc341d8

+ 36 - 0
src/api/order/list.js

@@ -0,0 +1,36 @@
+import request from "@/utils/request"
+
+// 列表
+export function list(data){
+  return request({
+    url: `/admin/order/page`,
+    method: 'post',
+    data
+  })
+}
+
+// 历史导出列表
+export function dialogList(data) {
+  return request({
+    url: `/admin/order/export/page`,
+    method: 'post',
+    data
+  })
+}
+
+// 导出
+export function download(data){
+  return request({
+    url: `/admin/order/excelDownload`,
+    method: 'post',
+    data
+  })
+}
+
+// 历史订单下载
+export function downLoadHistory(msgId) {
+  return request({
+    url: `/admin/order/getexportUrlBymsgId/${msgId}`,
+    method: 'get'
+  })
+}

+ 35 - 0
src/api/push/update.js

@@ -0,0 +1,35 @@
+import request from '@/utils/request'
+
+// 列表
+export function list(data) {
+  return request({
+    url: `/admin/appupdate/page`,
+    method: 'post',
+    data
+  })
+}
+
+// 详情
+export function detail(id) {
+  return request({
+    url: `/admin/appupdate/queryById/${id}`,
+    method: 'get'
+  })
+}
+
+// 新增 编辑
+export function submit(data) {
+  return request({
+    url: `/admin/appupdate/addOrUpdate`,
+    method: 'post',
+    data
+  })
+}
+
+// 删除
+export function remove(id, status) {
+  return request({
+    url: `/admin/appupdate/hitOrSold/${id}/${status}`,
+    method: 'get'
+  })
+}

+ 9 - 0
src/api/user/list.js

@@ -0,0 +1,9 @@
+import request from '@/utils/request'
+
+export function list(data) {
+  return request({
+    url: `/admin/user/page`,
+    method: 'post',
+    data
+  })
+}

+ 16 - 11
src/components/Upload/index.vue

@@ -1,9 +1,9 @@
 <template>
   <div class="upload">
-    <el-upload v-if="isBtn()" :action="action" :headers="headers" :multiple="multiple" :data="data"
-      :name="name" :show-file-list="showFileList" :drag="drag" :accept="accept" :listType="listType"
-      :autoUpload="autoUpload" :disabled="disabled" :before-upload="beforeUpload" :on-progress="onProgress"
-      :on-success="onSuccess" :on-error="onError">
+    <el-upload v-if="isBtn()" :action="action" :headers="headers" :multiple="multiple" :data="data" :name="name"
+      :show-file-list="showFileList" :drag="drag" :accept="accept" :listType="listType" :autoUpload="autoUpload"
+      :disabled="disabled" :before-upload="beforeUpload" :on-progress="onProgress" :on-success="onSuccess"
+      :on-error="onError">
       <el-button v-if="listType !== 'picture-card'" :type="type" ref="upload">
         <slot v-if="percentage <= 0 && !form.file">点击上传</slot>
         <span v-if="percentage > 0 && !form.file">{{ title }}</span>
@@ -61,6 +61,11 @@ export default {
     },
     // 最大允许上传个数
     limit: Number,
+    // 文件类型
+    accept: {
+      type: String,
+      default: ''
+    },
     // 图片尺寸
     width: Number,
     height: Number,
@@ -73,7 +78,8 @@ export default {
       obj: {
         'text': `${baseUrl}/system/file/file/upload`,
         'picture-card': `${baseUrl}/system/file/picture/upload`,
-        'audio': `${baseUrl}/system/file/mp3/upload`
+        'audio': `${baseUrl}/system/file/mp3/upload`,
+        'zip': `${baseUrl}/system/file/file/uploadFolderZip`
       },
       // 上传地址
       action: '#',
@@ -85,8 +91,6 @@ export default {
       data: {},
       // 文件名
       name: 'multipartFile',
-      // 文件类型
-      accept: '',
       // 进度条
       percentage: 0,
       title: '',
@@ -100,16 +104,17 @@ export default {
       }
     }
   },
-  watch:{
+  watch: {
     url(val) {
       this.form.file = val
+    },
+    listType(val) {
+      this.action = this.obj[val]
     }
   },
   created() {
     // 根据上传类型 变更 上传地址
     this.action = this.obj[this.listType]
-    // 根据上传类型 变更 文件类型
-    this.accept = this.listType === 'picture-card' ? '.jpg, .jpeg, .png, .bmp, .icon, .gif' : ''
     // 回显图片
     this.form.file = this.url
   },
@@ -184,7 +189,7 @@ export default {
 
     // 上传按钮
     isBtn() {
-      return ['text', 'audio'].includes(this.listType) || (this.listType === 'picture-card' && this.percentage == 0 && !this.form.file)
+      return ['text', 'audio', 'zip'].includes(this.listType) || (this.listType === 'picture-card' && this.percentage == 0 && !this.form.file)
     },
     // 显示进度条
     isPercentage() {

+ 17 - 1
src/mixin/index.js

@@ -545,6 +545,21 @@ const channelMixin = {
   }
 }
 
+// 手机系统
+const systemMixin = {
+  data() {
+    return {
+      systemOptions: [{
+        value: 1,
+        label: 'Android'
+      }, {
+        value: 2,
+        label: 'iOS'
+      }]
+    }
+  }
+}
+
 export {
   devMixin,
   devTypeMixin,
@@ -566,5 +581,6 @@ export {
   classifyMixin,
   currentMixin,
   coverMixin,
-  channelMixin
+  channelMixin,
+  systemMixin
 }

+ 18 - 3
src/router/index.js

@@ -196,7 +196,7 @@ export const dynamicRoutes = [{
     name: 'deviceListDetail',
     meta: {
       title: '设备详情',
-      activeMenu: '/device/list'
+      activeMenu: '/device/DeviceList'
     }
   }]
 },
@@ -570,8 +570,23 @@ export const dynamicRoutes = [{
       activeMenu: '/registration/exchangeConfig'
     }
   }]
-}
-]
+},
+// App升级
+{
+  path: '/push',
+  component: Layout,
+  hidden: true,
+  permissions: ['push:update:list'],
+  children: [{
+    path: 'update/detail',
+    component: () => import('@/views/push/update/detail'),
+    name: 'updateDetail',
+    meta: {
+      title: '升级详情',
+      activeMenu: '/push/update'
+    }
+  }]
+}]
 
 export default new Router({
   mode: 'history', // 去掉url中的#

+ 24 - 5
src/views/device/list/detail.vue

@@ -7,6 +7,9 @@
       <el-form-item label="设备名称:" prop="name">
         <el-input v-model="form.name" placeholder="请输入设备名称" />
       </el-form-item>
+      <el-form-item label="蓝牙名称:" prop="bluetoothName">
+        <el-input v-model="form.bluetoothName" placeholder="请输入蓝牙名称" />
+      </el-form-item>
       <el-form-item label="版本号:" prop="firstVersion">
         <el-input v-model="form.firstVersion" placeholder="请输入初始版本号" />
       </el-form-item>
@@ -29,6 +32,11 @@
           <el-option v-for="item in categoryOptions" :key="item.id" :label="item.name" :value="item.id" />
         </el-select>
       </el-form-item>
+      <el-form-item label="设备分类:" prop="deviceType">
+        <el-select v-model="form.deviceType" placeholder="请选择设备分类">
+          <el-option v-for="item in deviceTypeOptions" :key="item.value" :value="item.value" :label="item.label" />
+        </el-select>
+      </el-form-item>
       <el-form-item label="是否热门:" prop="isHot">
         <el-select v-model="form.isHot" placeholder="请选择是否热门">
           <el-option v-for="item in hotOptions" :key="item.value" :label="item.label" :value="Number(item.value)" />
@@ -45,7 +53,7 @@
           <el-form-item label="离线图片:" prop="offlineImg" style="float:right">
             <Upload listType="picture-card" :url="form.offlineImg" @upload="handleUploadImg($event, 'offline')"
               :disabled="disabled" />
-          </el-form-item>
+          </el-form-item> 
         </el-col>
       </el-row>
       <!-- 子表单 -->
@@ -93,15 +101,14 @@
           <el-input v-model="item.guideUrl" placeholder="请输入引导页网址" />
         </el-form-item>
         <el-form-item v-if="item.type === 1 || item.type === 3" label="引导页内容:"
-          :prop="`typeList.${index}.guidePageContent`"
-          :rules="{ required: true, message: '请输入引导页内容', trigger: 'blur' }">
+          :prop="`typeList.${index}.guidePageContent`" :rules="{ required: true, message: '请输入引导页内容', trigger: 'blur' }">
           <Editor v-model="item.guidePageContent" :min-height="250" :readOnly="disabled" />
         </el-form-item>
         <!-- 删除按钮 -->
         <el-link class="el-icon-close" v-if="form.typeList.length > 1" :underline="false" @click="getDelete(index)" />
       </div>
     </el-form>
-    <div class="form-btn">
+    <div style="margin-left: 120px;">
       <el-button @click="getCancel">取消</el-button>
       <el-button v-if="disabled === false" type="primary" @click="getSubmit">提交</el-button>
     </div>
@@ -137,10 +144,12 @@ export default {
       rules: {
         clientType: [{ required: true, message: "请输入设备型号", trigger: "blur" }],
         name: [{ required: true, message: "请输入设备名称", trigger: "blur" }],
+        bluetoothName: [{ required: true, message: '请输入蓝牙名称', trigger: 'blur' }],
         firstVersion: [{ required: true, message: "请输入初始版本号", trigger: "blur" }],
         upgradeType: [{ required: true, message: "请选择升级方式", trigger: "change" }],
         isHot: [{ required: true, message: "是否热门", trigger: "change" }],
         categoryId: [{ required: true, message: "请选择设备类型", trigger: "change" }],
+        deviceType: [{ required: true, message: "请选择设备分类", trigger: 'change' }],
         img: [{ required: true, message: "请上传在线图片", trigger: "change" }],
         offlineImg: [{ required: true, message: "请上传离线图片", trigger: "change" }],
       },
@@ -183,7 +192,17 @@ export default {
         label: 'QiXinWei'
       }],
       functionOptions: [],
-      categoryOptions: []
+      categoryOptions: [],
+      deviceTypeOptions: [{
+        value: 0,
+        label: '音响'
+      }, {
+        value: 1,
+        label: '耳机'
+      }, {
+        value: 2,
+        label: '穿戴'
+      }]
     };
   },
   mounted() {

+ 16 - 0
src/views/device/list/index.vue

@@ -32,12 +32,14 @@
       <el-table-column label="设备ID" prop="id" align="center" />
       <el-table-column label="设备型号" prop="clientType" align="center" />
       <el-table-column label="设备名称" prop="name" align="center" />
+      <el-table-column label="蓝牙名称" prop="bluetoothName" align="center" />
       <el-table-column label="设备图片" prop="img" align="center" width="100">
         <template slot-scope="scope">
           <el-image :src="scope.row.img" />
         </template>
       </el-table-column>
       <el-table-column label="设备类型" prop="categoryName" align="center" />
+      <el-table-column label="设备分类" prop="deviceType" align="center" :formatter="deviceTypeFormatter" />
       <el-table-column label="是否热门" prop="isHot" align="center" :formatter="hotFormatter" />
       <el-table-column label="升级方式" align="center" :formatter="upgradeTypeFormatter" />
       <el-table-column label="创建时间" prop="createTimeText" align="center" />
@@ -106,6 +108,16 @@ export default {
         value: 2,
         label: '指定'
       }],
+      deviceTypeOptions: [{
+        value: 0,
+        label: '音响'
+      }, {
+        value: 1,
+        label: '耳机'
+      }, {
+        value: 2,
+        label: '穿戴'
+      }]
     }
   },
   mounted() {
@@ -204,6 +216,10 @@ export default {
 
     upgradeTypeFormatter(row) {
       return this.selectDictLabel(this.upgradeTypeOptions, row.upgradeType)
+    },
+
+    deviceTypeFormatter(row) {
+      return this.selectDictLabel(this.deviceTypeOptions, row.deviceType)
     }
   }
 }

+ 52 - 67
src/views/device/version/detail.vue

@@ -14,13 +14,18 @@
       <el-form-item prop="version" label="版本号:">
         <el-input v-model="form.version" placeholder="请输入版本号" />
       </el-form-item>
+      <el-form-item label="上传类型:">
+        <el-select v-model="listType" placeholder="请选择上传类型" @change="handleChange">
+          <el-option v-for="item in updateOptions" :key="item.value" :value="item.value" :label="item.label" />
+        </el-select>
+      </el-form-item>
       <el-form-item prop="url" label="下载路径:">
         <el-row type="flex" justify="space-between">
           <el-col :span="16">
             <el-input v-model="form.url" placeholder="请输入 或 上传下载路径" clearable />
           </el-col>
           <el-col :span="6">
-            <Upload @upload="getUpload" style="float:right" />
+            <Upload :listType="listType" :accept="accept" @upload="getUpload" style="float:right" />
           </el-col>
         </el-row>
       </el-form-item>
@@ -47,8 +52,7 @@
       </el-form-item>
       <el-form-item prop="userType" label="升级对象:">
         <el-select v-model="form.userType" placeholder="请选择升级对象">
-          <el-option v-for="item in pushOptions" :key="item.value" :label="item.label"
-            :value="Number(item.value)" />
+          <el-option v-for="item in pushOptions" :key="item.value" :label="item.label" :value="Number(item.value)" />
         </el-select>
       </el-form-item>
       <el-form-item :prop="user" v-if="form.userType === 3" label="指定用户:">
@@ -79,69 +83,33 @@ export default {
       user: "",
       // 表单验证
       rules: {
-        deviceTypeId: [
-          {
-            required: true,
-            message: "请选择设备型号",
-            trigger: "change",
-          },
-        ],
-        type: [
-          {
-            required: true,
-            message: "请选择设备类型",
-            trigger: "change",
-          },
-        ],
-        version: [
-          {
-            required: true,
-            message: "请输入版本号",
-            trigger: "blur",
-          },
-        ],
-        url: [
-          {
-            required: true,
-            message: "请输入 或 上传下载路径",
-            trigger: "change",
-          },
-        ],
-        title: [
-          {
-            required: true,
-            message: "请输入升级标题",
-            trigger: "blur",
-          },
-        ],
-        content: [
-          {
-            required: true,
-            message: "请输入升级描述",
-            trigger: "blur",
-          },
-        ],
-        isEnforcement: [
-          {
-            required: true,
-            message: "是否强制升级",
-            trigger: "change",
-          },
-        ],
-        isPush: [
-          {
-            required: true,
-            message: "是否同步推送",
-            trigger: "change",
-          },
-        ],
-        userType: [
-          {
-            required: true,
-            message: "请选择推送类型",
-            trigger: "change",
-          },
-        ],
+        deviceTypeId: [{
+          required: true, message: "请选择设备型号", trigger: "change"
+        }],
+        type: [{
+          required: true, message: "请选择设备类型", trigger: "change"
+        }],
+        version: [{
+          required: true, message: "请输入版本号", trigger: "blur"
+        }],
+        url: [{
+          required: true, message: "请输入 或 上传下载路径", trigger: "change"
+        }],
+        title: [{
+          required: true, message: "请输入升级标题", trigger: "blur"
+        }],
+        content: [{
+          required: true, message: "请输入升级描述", trigger: "blur"
+        }],
+        isEnforcement: [{
+          required: true, message: "是否强制升级", trigger: "change"
+        }],
+        isPush: [{
+          required: true, message: "是否同步推送", trigger: "change"
+        }],
+        userType: [{
+          required: true, message: "请选择推送类型", trigger: "change"
+        }],
       },
       // 设备是否
       statusOptions: [{
@@ -158,7 +126,18 @@ export default {
       }, {
         value: 3,
         label: '指定'
-      }]
+      }],
+      // 上传类型
+      updateOptions: [{
+        value: 'text',
+        label: '文件'
+      }, {
+        value: 'zip',
+        label: '文件夹'
+      }],
+      listType: 'text',
+      // 文件类型
+      accept: '.bin'
     };
   },
   mounted() {
@@ -178,6 +157,12 @@ export default {
     getUpload(e) {
       this.form.url = e.file;
     },
+
+    // 上传类型
+    handleChange(e) {
+      this.accept = e === 'text' ? '.bin' : '.zip'
+    },
+
     // 提交
     getSubmit() {
       this.$refs.form.validate((valid) => {

+ 1 - 1
src/views/operation/recommend/index.vue

@@ -98,7 +98,7 @@
               </el-select>
             </el-form-item>
 
-            <el-form-item label="专区页面:" v-if="item.forwardType === 7">
+            <el-form-item label="专区页面:" v-if="forwardType() && item.forwardType === 7">
               <el-select v-model="item.contentId" placeholder="请选择跳转专区">
                 <el-option v-for="item in sceneOptions" :key="item.value" :value="item.value" :label="item.label" />
               </el-select>

+ 327 - 0
src/views/order/list/index.vue

@@ -0,0 +1,327 @@
+<template>
+  <div class="app-container">
+    <!-- 搜索 -->
+    <el-form inline size="mini">
+      <el-form-item label="订单编号:">
+        <el-input v-model="form.orderCode" placeholder="请输入订单编号" clearable />
+      </el-form-item>
+      <el-form-item label="用户账号:">
+        <el-input v-model="form.userName" placeholder="请输入用户账户" clearable />
+      </el-form-item>
+      <el-form-item label="用户手机号:">
+        <el-input v-model="form.phone" placeholder="请输入用户手机号" clearable />
+      </el-form-item>
+      <!-- 流量订单 -->
+      <span v-if="form.searchType === '2'">
+        <el-form-item label="SIM卡号:">
+          <el-input v-model="form.simCode" placeholder="请输入SIM卡号" clearable />
+        </el-form-item>
+        <el-form-item label="生效状态">
+          <el-select v-model="form.flowStatus" placeholder="请选择生效状态">
+            <el-option v-for="item in flowOptions" :key="item.value" :value="item.value" :label="item.label" />
+          </el-select>
+        </el-form-item>
+      </span>
+      <!-- 除充值订单 -->
+      <span v-if="form.searchType === '3'">
+        <el-form-item label="商品ID:">
+          <el-input v-model="form.goodsid" placeholder="请输入商品ID" />
+        </el-form-item>
+        <el-form-item label="商品名称:">
+          <el-input v-model="form.goodsName" placeholder="请输入商品名称" />
+        </el-form-item>
+        <el-form-item label="操作系统">
+          <el-select v-model="form.platform" placeholder="请选择操作系统">
+            <el-option v-for="item in systemOptions" :key="item.value" :value="item.value" :label="item.label" />
+          </el-select>
+        </el-form-item>
+      </span>
+      <!-- 会员订单 -->
+      <el-form-item v-if="form.searchType === '4'" label="资源平台:">
+        <el-select v-model="form.platformId" placeholder="请选择资源平台">
+          <el-option v-for="item in platformIdOptions" :key="item.value" :value="item.value" :label="item.label" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="支付状态:">
+        <el-select v-model="form.status" placeholder="请选择订单状态">
+          <el-option v-for="item in statusOptions" :key="item.value" :value="item.value" :label="item.label" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="支付方式:">
+        <el-select v-model="form.payType" placeholder="请选择支付方式">
+          <el-option v-for="item in payOptions" :key="item.value" :value="item.value" :label="item.label" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="下单时间:">
+        <el-date-picker v-model="form.listDate" type="datetimerange" start-placeholder="开始日期" end-placeholder="结束日期"
+          value-format="yyyy-MM-dd HH:mm:ss" />
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" @click="getSearch">搜索</el-button>
+        <el-button icon="el-icon-refresh" @click="getRefresh">重置</el-button>
+        <el-button type="primary" icon="el-icon-download" @click="handleExport">导出</el-button>
+        <el-button type="primary" @click="getDialog">查看</el-button>
+      </el-form-item>
+    </el-form>
+    <!-- 列表 -->
+    <el-table :data="tableData" v-loading="loading">
+      <el-table-column label="订单编号" prop="orderCode" key="orderCode" align="center" />
+      <el-table-column v-if="form.searchType === '2'" label="第三方订单编号" prop="thirdOrderId" key="thirdOrderId"
+        align="center" />
+      <el-table-column label="商品ID" prop="goodsid" key="goodsid" align="center" />
+      <el-table-column label="商品名称" prop="goodsName" key="goodsName" align="center" show-overflow-tooltip />
+      <el-table-column label="订单金额 / 元" prop="amount" key="amount" align="center" :formatter="amountFormatter" />
+      <el-table-column v-if="form.searchType === '2'" label="SIM卡号" prop="simCode" key="simCode" align="center" />
+      <el-table-column v-if="form.searchType === '1'" label="购买类型" prop="charging" key="charging" align="center"
+        :formatter="chargingFormatter" />
+      <el-table-column v-if="form.searchType === '3'" label="订单来源" prop="platform" key="platform" align="center"
+        :formatter="platformFormatter" />
+      <el-table-column v-if="form.searchType === '4'" label="栏目" prop="groupId" key="groupId" align="center"
+        :formatter="groupFormatter" />
+      <el-table-column v-if="form.searchType === '4'" label="服务时长" prop="expirationTime" key="expirationTime"
+        align="center" />
+      <el-table-column v-if="form.searchType === '4'" label="资源平台" prop="platformId" key="platformId" align="center"
+        :formatter="platformIdFormatter" />
+      <el-table-column label="下单时间" prop="createTime" key="createTime" align="center" />
+      <el-table-column label="支付方式" prop="payType" key="payType" align="center" :formatter="payTypeFormatter" />
+      <el-table-column label="支付状态" prop="status" key="status" align="center" :formatter="statusFormatter" />
+      <el-table-column label="支付时间" prop="goodsUpdateTime" key="goodsUpdateTime" align="center" />
+      <el-table-column label="用户账号" prop="userName" key="userName" align="center" />
+      <el-table-column label="支付流水号" prop="payId" key="payId" align="center" />
+      <el-table-column v-if="form.searchType === '2'" label="生效状态" prop="flowStatus" key="flowStatus" align="center"
+        :formatter="flowFormatter" />
+      <el-table-column v-if="form.searchType === '2'" label="生效时间" prop="effectTime" key="effectTime" align="center" />
+    </el-table>
+    <pagination v-show="total > 0" :total="total" :page.sync="form.pageNum" :limit.sync="form.pageSize"
+      @pagination="getList" />
+    <!-- 弹窗 -->
+    <el-dialog :visible.sync="dialogVisible" title="导出历史" width="1000px">
+      <el-table :data="dialogTable" v-loading="dialogLoading">
+        <el-table-column type="index" label="序号" align="center" />
+        <el-table-column label="任务ID" prop="msgId" align="center" />
+        <el-table-column label="任务名称" prop="jobName" align="center" />
+        <el-table-column label="任务类型" prop="jobType" align="center" />
+        <el-table-column label="导出时间" prop="updateTime" align="center" />
+        <el-table-column label="操作" align="center">
+          <template slot-scope="scope">
+            <el-button type="text" @click="getDownLoad(scope.row)" :disabled="scope.row.status === 1">下载</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+      <pagination v-show="dialogTotal > 0" :total="dialogTotal" :page.sync="form.pageNum" :limit.sync="form.pageSize"
+        @pagination="getList" />
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { list, dialogList, download, downLoadHistory } from '@/api/order/list'
+import { list as sceneList } from '@/api/operation/scene'
+import { payTypeMixin, systemMixin } from '@/mixin/index'
+export default {
+  mixins: [payTypeMixin, systemMixin],
+  data() {
+    return {
+      // 遮罩层
+      loading: false,
+      dialogLoading: false,
+      // 表单
+      form: {
+        pageNum: 1,
+        pageSize: 10,
+        searchType: this.$route.query.searchType
+      },
+      // 列表
+      tableData: [],
+      // 总数据
+      total: 0,
+      // 弹窗
+      dialogVisible: false,
+      // 弹窗表单
+      dialogForm: {
+        pageNum: 1,
+        pageSize: 10
+      },
+      // 弹窗列表
+      dialogTable: [],
+      // 历史数据
+      dialogTotal: 0,
+      // 支付方式
+      payOptions: [{
+        value: 1,
+        label: '微信'
+      }, {
+        value: 2,
+        label: '支付宝'
+      }, {
+        value: 3,
+        label: '苹果支付'
+      }, {
+        value: 4,
+        label: '猫币支付'
+      }],
+      // 支付状态
+      statusOptions: [{
+        value: 1,
+        label: '待支付'
+      }, {
+        value: 2,
+        label: '支付成功'
+      }, {
+        value: 3,
+        label: '支付失败'
+      }, {
+        value: 4,
+        label: '取消'
+      }],
+      // 栏目
+      sceneOptions: [],
+      // 生效状态
+      flowOptions: [{
+        value: 0,
+        label: '已生效'
+      }, {
+        value: 1,
+        label: '待生效'
+      }, {
+        value: 2,
+        label: '已失效'
+      }],
+      platformIdOptions: [{
+        value: 6,
+        label: 'QQ音乐'
+      }, {
+        value: 9,
+        label: '酷狗音乐'
+      }, {
+        value: 10,
+        label: '爱听音乐'
+      }]
+    }
+  },
+  mounted() {
+    this.getScene()
+    this.getList()
+  },
+  methods: {
+    // 列表
+    getList() {
+      this.loading = true
+      list(this.form).then(res => {
+        if (res.code === 0) {
+          this.tableData = res.data.records
+          this.total = res.data.total
+          this.loading = false
+        }
+      })
+    },
+
+    // 搜索
+    getSearch() {
+      this.form.pageNum = 1
+      this.getList()
+    },
+
+    // 重置
+    getRefresh() {
+      this.form = {
+        pageNum: 1,
+        pageSize: 10,
+        searchType: this.$route.query.searchType
+      }
+      this.getList()
+    },
+
+    // 导出
+    handleExport() {
+      download(this.form).then(res => {
+        if (res.code === 0) {
+          this.$message.success(`${res.data}`)
+        }
+      })
+    },
+
+    // 弹窗
+    getDialog() {
+      this.dialogVisible = true
+      this.getDialogList()
+    },
+
+    // 历史列表
+    getDialogList() {
+      this.dialogLoading = true
+      dialogList(this.dialogForm).then(res => {
+        if (res.code === 0) {
+          this.dialogTable = res.data.records
+          this.dialogTotal = res.data.total
+          this.dialogLoading = false
+        }
+      })
+    },
+
+    // 历史下载
+    getDownLoad(row) {
+      this.$confirm(`是否下载${row.jobName}?`, '提示', {
+        type: 'warning'
+      }).then(() => {
+        downLoadHistory(row.msgId).then(res => {
+          if (res.code === 0) {
+            this.$message.success('下载成功!')
+            window.location.href = res.data
+            this.getDialogList()
+          }
+        })
+      }).catch(() => { })
+    },
+
+    // 栏目
+    getScene() {
+      sceneList().then(res => {
+        if (res.code === 0) {
+          res.data.map(i => {
+            this.sceneOptions.push({
+              value: i.id,
+              label: i.name
+            })
+          })
+        }
+      })
+    },
+
+    // 字典翻译
+    payTypeFormatter(row) {
+      return this.selectDictLabel(this.payOptions, row.payType)
+    },
+
+    statusFormatter(row) {
+      return this.selectDictLabel(this.statusOptions, row.status)
+    },
+
+    groupFormatter(row) {
+      return this.selectDictLabel(this.sceneOptions, row.groupId)
+    },
+
+    chargingFormatter(row) {
+      return this.selectDictLabel(this.payTypeOptions, row.charging)
+    },
+
+    platformFormatter(row) {
+      return this.selectDictLabel(this.systemOptions, row.platform)
+    },
+
+    platformIdFormatter(row) {
+      return this.selectDictLabel(this.platformIdOptions, row.platformId)
+    },
+
+    flowFormatter(row) {
+      return this.selectDictLabel(this.flowOptions, row.flowStatus)
+    },
+
+    amountFormatter(row) {
+      return row.amount.toFixed(2)
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped></style>

+ 135 - 0
src/views/push/update/detail.vue

@@ -0,0 +1,135 @@
+<template>
+  <div class="app-container">
+    <el-form :model="form" ref="form" :rules="rules" label-width="100px" :disabled="disabled">
+      <el-form-item label="版本号:" prop="lastVersion">
+        <el-input v-model="form.lastVersion" placeholder="请输入版本号" />
+      </el-form-item>
+      <el-form-item label="升级标题:" prop="updateTitle">
+        <el-input v-model="form.updateTitle" placeholder="请输入升级标题" maxlength="100" show-word-limit />
+      </el-form-item>
+      <el-form-item label="升级说明:" prop="updateDesc">
+        <el-input v-model="form.updateDesc" type="textarea" :autosize="{ minRows: 5, maxRows: 10 }" placeholder="请输入升级说明"
+          maxlength="500" show-word-limit />
+      </el-form-item>
+      <el-form-item label="强制升级:" prop="isForceUpdate">
+        <el-select v-model="form.isForceUpdate" placeholder="请选择是否强制">
+          <el-option v-for="item in typeOptions" :key="item.value" :value="item.value" :label="item.label" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="升级系统:" prop="appType">
+        <el-select v-model="form.appType" placeholder="请选择升级系统">
+          <el-option v-for="item in systemOptions" :key="item.value" :value="item.value" :label="item.label" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="下载路径:" prop="downUrl">
+        <el-row type="flex" justify="space-between">
+          <el-col :span="16">
+            <el-input v-model="form.downUrl" placeholder="请输入或上传下载路径" />
+          </el-col>
+          <el-col :span="6">
+            <Upload @upload="upload" style="float:right" />
+          </el-col>
+        </el-row>
+      </el-form-item>
+    </el-form>
+    <div class="form-btn">
+      <el-button @click="cancel">取消</el-button>
+      <el-button v-if="!disabled" type="primary" @click="getSubmit">确定</el-button>
+    </div>
+  </div>
+</template>
+
+<script>
+import { detail, submit } from '@/api/push/update'
+import { systemMixin } from '@/mixin'
+export default {
+  mixins: [systemMixin],
+  data() {
+    var checkVersion = (rule, value, callback) => {
+      if (!value) {
+        return callback(new Error('请输入版本号'))
+      }
+      let reg = /^[1-9](\.(0|[1-9])){2}$/
+      if (reg.test(value)) {
+        callback()
+      } else {
+        return callback(new Error('请输入正确的版本号,示例:x.x.x'))
+      }
+    }
+    return {
+      // 表单
+      form: {
+        downUrl: ""
+      },
+      // 只读
+      disabled: false,
+      // 是否强制
+      typeOptions: [{
+        value: 0,
+        label: '否'
+      }, {
+        value: 1,
+        label: '是'
+      }],
+      // 校验
+      rules: {
+        lastVersion: [{ required: true, validator: checkVersion, trigger: 'blur' }],
+        updateTitle: [{ required: true, message: '请输入升级标题', trigger: 'blur' }],
+        updateDesc: [{ required: true, message: '请输入升级说明', trigger: 'blur' }],
+        isForceUpdate: [{ required: true, message: '请选择是否强制', trigger: 'change' }],
+        appType: [{ required: true, message: '请选择升级系统', trigger: 'change' }],
+        downUrl: [{ required: true, message: '请上传下载路径', trigger: 'blur' }]
+      }
+    }
+  },
+  mounted() {
+    if (this.$route.query.id) {
+      this.form.id = this.$route.query.id
+      this.disabled = Boolean(this.$route.query.boolean)
+      this.getDetail()
+    }
+  },
+  methods: {
+    // 详情
+    getDetail() {
+      detail(this.form.id).then(res => {
+        if (res.code === 0) {
+          this.form = res.data
+        }
+      })
+    },
+
+    // 上传
+    upload(e) {
+      this.form.downUrl = e.file
+    },
+
+    // 取消
+    cancel() {
+      this.$tab.closeOpenPage("/push/update");
+    },
+
+    // 确定
+    getSubmit() {
+      this.$refs.form.validate((valid) => {
+        if (valid) {
+          submit(this.form).then(res => {
+            if (res.code === 0) {
+              this.$message.success('提交成功!')
+              this.cancel()
+            }
+          })
+        } else {
+          return false
+        }
+      })
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.el-form {
+  width: 500px;
+}
+</style>

+ 136 - 0
src/views/push/update/index.vue

@@ -0,0 +1,136 @@
+<template>
+  <div class="app-container">
+    <!-- 搜索 -->
+    <el-form size="mini" inline>
+      <el-form-item label="版本号:">
+        <el-input v-model="form.lastVersion" placeholder="请输入版本号" clearable />
+      </el-form-item>
+      <el-form-item label="升级系统:">
+        <el-select v-model="form.appType" placeholder="请选择升级系统" clearable>
+          <el-option v-for="item in systemOptions" :key="item.value" :value="item.value" :label="item.label" />
+        </el-select>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" @click="getSearch">搜索</el-button>
+        <el-button icon="el-icon-refresh" @click="getRefresh">重置</el-button>
+        <el-button type="primary" icon="el-icon-plus" plain @click="getDetail()">新增</el-button>
+      </el-form-item>
+    </el-form>
+    <!-- 列表 -->
+    <el-table :data="tableData" v-loading="loading">
+      <el-table-column type="index" label="序号" align="center" />
+      <el-table-column label="升级标题" prop="updateTitle" align="center" show-overflow-tooltip />
+      <el-table-column label="版本号" prop="lastVersion" align="center" />
+      <el-table-column label="下载路径" prop="downUrl" align="center" show-overflow-tooltip />
+      <el-table-column label="是否强制升级" prop="isForceUpdate" align="center" :formatter="typeFormatter" />
+      <el-table-column label="升级系统" prop="appType" align="center" :formatter="appTypeFormatter" />
+      <el-table-column label="更新时间" prop="updateTime" align="center" />
+      <el-table-column label="操作" align="center">
+        <template slot-scope="scope">
+          <el-button type="text" @click="getDetail(scope.row.id, true)">查看</el-button>
+          <el-button type="text" @click="getDetail(scope.row.id)">编辑</el-button>
+          <el-button type="delete" @click="getDelete(scope.row)">删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    <pagination v-show="total > 0" :total="total" :page.sync="form.pageNum" :limit.sync="form.pageSize"
+      @pagination="getList" />
+  </div>
+</template>
+
+<script>
+import { list, remove } from '@/api/push/update'
+import { systemMixin } from '@/mixin'
+export default {
+  mixins: [systemMixin],
+  data() {
+    return {
+      // 遮罩层
+      loading: false,
+      // 表单
+      form: {
+        pageNum: 1,
+        pageSize: 10
+      },
+      // 列表
+      tableData: [],
+      // 总数据
+      total: 0,
+      // 是否强制
+      typeOptions: [{
+        value: 0,
+        label: '否'
+      }, {
+        value: 1,
+        label: '是'
+      }]
+    }
+  },
+  mounted() {
+    this.getList()
+  },
+  methods: {
+    // 列表
+    getList() {
+      this.loading = true
+      list(this.form).then(res => {
+        if (res.code === 0) {
+          this.tableData = res.data.records
+          this.total = res.data.total
+          this.loading = false
+        }
+      })
+    },
+    // 搜索
+    getSearch() {
+      this.form.pageNum = 1
+      this.getList()
+    },
+
+    // 重置
+    getRefresh() {
+      this.form = {
+        pageNum: 1,
+        pageSize: 10
+      }
+      this.getList()
+    },
+
+    // 新增 编辑
+    getDetail(id, boolean) {
+      this.$router.push({
+        path: '/push/update/detail',
+        query: {
+          id: id,
+          boolean: boolean
+        }
+      })
+    },
+
+    // 删除
+    getDelete(row) {
+      this.$confirm(`是否删除${row.updateTitle}?`, '提示', {
+        type: 'warning'
+      }).then(() => {
+        remove(row.id, 1).then(res => {
+          if (res.code === 0) {
+            this.$message.success('删除成功!')
+            this.getList()
+          }
+        })
+      }).catch(() => { })
+    },
+
+    // 字典翻译
+    typeFormatter(row) {
+      return this.selectDictLabel(this.typeOptions, row.isForceUpdate)
+    },
+
+    appTypeFormatter(row) {
+      return this.selectDictLabel(this.systemOptions, row.appType)
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped></style>

+ 10 - 26
src/views/service/qqmusic/index.vue

@@ -3,20 +3,16 @@
     <!-- 搜索 -->
     <el-form inline size="mini">
       <el-form-item label="批次:">
-        <el-select v-model="form.batchId" placeholder="请选择批次" clearable>
-          <el-option v-for="item in batchOptions" :key="item.value" :label="item.label" :value="item.value" />
-        </el-select>
+        <el-input v-model="form.no" placeholder="请输入批次" clearable />
       </el-form-item>
       <el-form-item label="服务时长:">
         <el-select v-model="form.serviceTime" placeholder="请选择服务时长" clearable>
-          <el-option v-for="item in serviceTimeOptions" :key="item.value" :label="item.label"
-            :value="item.value" />
+          <el-option v-for="item in serviceTimeOptions" :key="item.value" :label="item.label" :value="item.value" />
         </el-select>
       </el-form-item>
       <el-form-item label="当前状态:">
         <el-select v-model="form.status" placeholder="请选择当前状态" clearable>
-          <el-option v-for="item in statusOptions" :key="item.value" :label="item.label"
-            :value="item.value" />
+          <el-option v-for="item in statusOptions" :key="item.value" :label="item.label" :value="item.value" />
         </el-select>
       </el-form-item>
       <el-form-item label="用户姓名:">
@@ -27,8 +23,7 @@
       </el-form-item>
       <el-form-item label="激活状态:">
         <el-select v-model="form.activeStatus" placeholder="请选择激活状态" clearable>
-          <el-option v-for="item in activeOptions" :key="item.value" :value="item.value"
-            :label="item.label" />
+          <el-option v-for="item in activeOptions" :key="item.value" :value="item.value" :label="item.label" />
         </el-select>
       </el-form-item>
       <el-form-item>
@@ -59,7 +54,7 @@
       </el-table-column>
     </el-table>
     <!-- 分页 -->
-    <pagination v-show="total>0" :total="total" :page.sync="form.pageNum" :limit.sync="form.pageSize"
+    <pagination v-show="total > 0" :total="total" :page.sync="form.pageNum" :limit.sync="form.pageSize"
       @pagination="getList" />
     <!-- 弹窗 -->
     <el-dialog :visible.sync="dialogVisible" :title="title">
@@ -67,8 +62,7 @@
       <el-form v-if="title === '批量推送短信'">
         <el-form-item label="服务时长:" label-width="100px" style="width: 300px">
           <el-select v-model="dialogForm.serviceTime" placeholder="请选择服务时长">
-            <el-option v-for="item in serviceTimeOptions" :key="item.value" :label="item.label"
-              :value="item.value" />
+            <el-option v-for="item in serviceTimeOptions" :key="item.value" :label="item.label" :value="item.value" />
           </el-select>
         </el-form-item>
         <el-form-item>
@@ -104,7 +98,7 @@
           </el-table-column>
         </el-table>
         <!-- 分页 -->
-        <pagination v-show="batchTotal>0" :total="batchTotal" :page.sync="batchForm.pageNum"
+        <pagination v-show="batchTotal > 0" :total="batchTotal" :page.sync="batchForm.pageNum"
           :limit.sync="batchForm.pageSize" @pagination="getBatchPage" />
       </div>
 
@@ -174,7 +168,7 @@ export default {
         value: 2,
         label: '删除'
       }],
-      batchOptions: [],
+      // batchOptions: [], (3.0.6版本舍弃)
       // 当前状态
       statusOptions: [
         { value: 0, label: '已发送' },
@@ -188,17 +182,7 @@ export default {
     }
   },
   mounted() {
-    // 批次列表
-    batchList().then(res => {
-      if (res.code === 0) {
-        res.data.map(i => {
-          this.batchOptions.push({
-            value: i.id,
-            label: i.no
-          })
-        })
-      }
-    })
+    // this.getBatchList() (3.0.6版本舍弃)
     this.getList()
   },
   methods: {
@@ -213,7 +197,7 @@ export default {
         }
       })
     },
-
+    
     // 搜索
     getSearch() {
       this.form.pageNum = 1

+ 228 - 0
src/views/user/list/index.vue

@@ -0,0 +1,228 @@
+<template>
+  <div class="app-container">
+    <!-- 搜索 -->
+    <el-form inline size="mini">
+      <el-form-item label="用户账号:">
+        <el-input v-model="form.userName" placeholder="请输入用户账号" clearable />
+      </el-form-item>
+      <el-form-item label="用户手机号:">
+        <el-input v-model="form.phone" placeholder="请输入用户手机号" clearable />
+      </el-form-item>
+      <el-form-item label="注册来源:">
+        <el-select v-model="form.registerChannel" placeholder="请选择注册来源" clearable>
+          <el-option v-for="item in regOptions" :key="item.value" :value="item.value" :label="item.label" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="注册时间:">
+        <el-date-picker v-model="form.startsignTime" type="datetimerange" start-placeholder="开始日期"
+          end-placeholder="结束日期" />
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" @click="getSearch">搜索</el-button>
+        <el-button icon="el-icon-refresh" @click="getRefresh">重置</el-button>
+      </el-form-item>
+    </el-form>
+    <!-- 列表 -->
+    <el-table :data="tableData" v-loading="loading">
+      <el-table-column label="用户ID" prop="id" align="center" show-overflow-tooltip />
+      <el-table-column label="用户账号" prop="nickname" align="center" />
+      <el-table-column label="用户手机号" prop="phone" align="center" />
+      <el-table-column label="用户头像" align="center" width="100px">
+        <template slot-scope="scope">
+          <el-image :src="scope.row.headUrl" />
+        </template>
+      </el-table-column>
+      <el-table-column label="用户性别" prop="sex" align="center" :formatter="sexFormatter" />
+      <el-table-column label="注册来源" prop="registerChannel" align="center" :formatter="regFormatter" />
+      <el-table-column label="注册系统" prop="mtype" align="center" :formatter="typeFormatter" />
+      <el-table-column label="注册时间" prop="createTime" align="center" />
+      <el-table-column label="用户积分" align="center">
+        <template slot-scope="scope">
+          <span>{{ scope.row.totalPoint | empty(scope.row.totalPoint) }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column align="center">
+        <template slot="header">
+          <div>钱包余额</div>
+          <div>(Android)</div>
+        </template>
+        <template slot-scope="scope">
+          <span>{{ scope.row.balanceAndroid.toFixed(2) }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column align="center">
+        <template slot="header">
+          <div>钱包余额</div>
+          <div>(iOS)</div>
+        </template>
+        <template slot-scope="scope">
+          <span>{{ scope.row.balanceIos.toFixed(2) }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="已绑设备" align="center" show-overflow-tooltip>
+        <template slot-scope="scope">
+          <span v-if="scope.row.deviceList">
+            {{ scope.row.deviceList.join(',') }}
+          </span>
+          <span v-else>
+            暂无绑定
+          </span>
+        </template>
+      </el-table-column>
+      <el-table-column label="购买次数" align="center">
+        <template slot-scope="scope">
+          <span>{{ scope.row.buyCount | empty(scope.row.buyCount) }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="累计消费 / 元" align="center">
+        <template slot-scope="scope">
+          <span>{{ scope.row.buyAmount | emptyCount(scope.row.buyAmount) }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="上次消费" prop="lastBuyTime" align="center">
+        <template slot-scope="scope">
+          <span>{{ scope.row.lastBuyTime | emptyDate(scope.row.lastBuyTime) }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="累计充值 / 元" prop="rechargeAmount" align="center">
+        <template slot-scope="scope">
+          <span>{{ scope.row.rechargeAmount | emptyCount(scope.row.rechargeAmount) }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="上次充值" prop="lastRechargeTime" align="center">
+        <template slot-scope="scope">
+          <span>{{ scope.row.lastRechargeTime | emptyDate(scope.row.lastRechargeTime) }}</span>
+        </template>
+      </el-table-column>
+    </el-table>
+    <pagination v-show="total > 0" :total="total" :page.sync="form.pageNum" :limit.sync="form.pageSize"
+      @pagination="getList" />
+  </div>
+</template>
+
+<script>
+import { list } from '@/api/user/list'
+import { sexMixin } from '@/mixin/index'
+export default {
+  mixins: [sexMixin],
+  data() {
+    return {
+      // 遮罩层
+      loading: false,
+      // 表单
+      form: {
+        pageNum: 1,
+        pageSize: 10
+      },
+      // 列表
+      tableData: [],
+      // 总数据
+      total: 0,
+      // 注册来源
+      regOptions: [{
+        value: -1,
+        label: '未知'
+      }, {
+        value: 0,
+        label: '小米应用市场'
+      }, {
+        value: 1,
+        label: '360应用市场'
+      }, {
+        value: 2,
+        label: '腾讯应用市场'
+      }, {
+        value: 3,
+        label: 'OPPP应用市场'
+      }, {
+        value: 4,
+        label: 'ViVO应用市场'
+      }, {
+        value: 5,
+        label: '魅族应用市场'
+      }, {
+        value: 6,
+        label: '华为应用市场'
+      }, {
+        value: 7,
+        label: '微信小程序'
+      }],
+      // 注册系统
+      typeOptions: [{
+        value: 0,
+        label: '默认值'
+      }, {
+        value: 1,
+        label: 'Android'
+      }, {
+        value: 2,
+        label: 'iOS'
+      }]
+    }
+  },
+  mounted() {
+    this.getList()
+  },
+  methods: {
+    // 列表
+    getList() {
+      this.loading = true
+      list(this.form).then(res => {
+        if (res.code === 0) {
+          this.tableData = res.data.records
+          this.total = res.data.total
+          this.loading = false
+        }
+      })
+    },
+
+    // 搜索
+    getSearch() {
+      this.form.pageNum = 1
+      this.getList()
+    },
+
+    // 重置
+    getRefresh() {
+      this.form = {
+        pageNum: 1,
+        pageSize: 10
+      }
+      this.getList()
+    },
+
+    // 字典翻译
+    regFormatter(row) {
+      return this.selectDictLabel(this.regOptions, row.registerChannel)
+    },
+
+    sexFormatter(row) {
+      return this.selectDictLabel(this.sexOptions, row.sex)
+    },
+
+    typeFormatter(row) {
+      return this.selectDictLabel(this.typeOptions, row.mtype)
+    }
+  },
+
+  // 过滤器
+  filters: {
+    // 是否为空
+    empty(item) {
+      return !item ? 0 : item
+    },
+
+    // 金额是否为空
+    emptyCount(item) {
+      return !item ? '0.00' : Number(item).toFixed(2)
+    },
+
+    // 时间为空
+    emptyDate(item) {
+      return !item ? '-' : item
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped></style>