DESKTOP-SVI9JE1\muzen 1 рік тому
батько
коміт
f05f96448c

+ 35 - 0
src/api/operation/feedbacklist.js

@@ -0,0 +1,35 @@
+import request from '@/utils/request'
+
+// 列表
+export function list(data) {
+  return request({
+    url: `/admin/opinions/list`,
+    method: 'post',
+    data
+  })
+}
+
+// 详情
+export function detail(id) {
+  return request({
+    url: `/admin/opinions/queryById/${id}`,
+    method: 'get'
+  })
+}
+
+// 提交
+export function submit(data) {
+  return request({
+    url: `/admin/opinions/reply`,
+    method: 'post',
+    data
+  })
+}
+
+// 反馈类型列表
+export function typeList() {
+  return request({
+    url: `/admin/opinions/typeList`,
+    method: 'post'
+  })
+}

+ 35 - 0
src/api/operation/feedbacktype.js

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

+ 9 - 0
src/api/service/qqmusic.js

@@ -9,6 +9,15 @@ export function page(data) {
   })
 }
 
+// 兑换码列表
+export function list(data) {
+  return request({
+    url: `/qqServiceBatch/newpage`,
+    method: 'post',
+    data
+  })
+}
+
 // 批量导入推送短信
 export function importData(data){
   return request({

Різницю між файлами не показано, бо вона завелика
+ 1 - 0
src/assets/icons/svg/tts.svg


+ 4 - 0
src/common/main.scss

@@ -81,4 +81,8 @@
 input::-webkit-outer-spin-button,
 input::-webkit-inner-spin-button {
   -webkit-appearance: none;
+}
+
+.el-tooltip__popper {
+  width: 500px;
 }

+ 1 - 1
src/mixin/index.js

@@ -344,7 +344,7 @@ const payTypeMixin = {
         label: '免费'
       }, {
         value: 2,
-        label: '全购买'
+        label: '全购买'
       }, {
         value: 3,
         label: '单集购买'

+ 35 - 18
src/router/index.js

@@ -166,22 +166,22 @@ export const dynamicRoutes = [{
   }]
 },
 // 内容管理
-// banner管理
-{
-  path: '/content',
-  component: Layout,
-  hidden: true,
-  permissions: ['content:banner:list'],
-  children: [{
-    path: 'banner/detail',
-    component: () => import('@/views/content/banner/detail'),
-    name: 'detail',
-    meta: {
-      title: 'Banner详情',
-      activeMenu: '/content/banner'
-    }
-  }]
-},
+// 文章管理
+// {
+//   path: '/content',
+//   component: Layout,
+//   hidden: true,
+//   permissions: ['content:article:list'],
+//   children: [{
+//     path: 'articleList/detail',
+//     component: () => import('@/views/content/article/detail'),
+//     name: 'articleListDetail',
+//     meta: {
+//       title: '文章详情',
+//       activeMenu: '/content/articleList'
+//     }
+//   }]
+// },
 // 设备管理
 // 设备列表
 {
@@ -428,7 +428,7 @@ export const dynamicRoutes = [{
   hidden: true,
   permissions: ['operation:recommend:list'],
   children: [{
-    path: 'recommend/detail',
+    path: 'homePage/recommend/detail',
     component: () => import('@/views/operation/recommend/detail'),
     name: 'recommendDetail',
     meta: {
@@ -523,7 +523,7 @@ export const dynamicRoutes = [{
   }]
 },
 // 活动管理
-{ 
+{
   path: '/operation',
   component: Layout,
   hidden: true,
@@ -539,6 +539,23 @@ export const dynamicRoutes = [{
     }
   }]
 },
+// 反馈列表
+{
+  path: '/operation',
+  component: Layout,
+  hidden: true,
+  permissions: ['operation:feedbacklist:list'],
+  name: 'feedbacklist',
+  children: [{
+    path: 'feedback/feedbacklist/detail',
+    component: () => import('@/views/operation/feedbacklist/detail'),
+    name: 'feedbacklistDetail',
+    meta: {
+      title: '反馈详情',
+      activeMenu: '/operation/feedback/feedbacklist'
+    }
+  }]
+},
 // 商品管理
 // 商品推荐
 {

+ 0 - 58
src/views/content/autoFM/detail.vue

@@ -1,58 +0,0 @@
-<template>
-  <div class="app-container">
-    <el-form label-width="auto">
-      <el-form-item label="海外电台ID:">
-        <span>123</span>
-      </el-form-item>
-      <el-form-item label="电台名称:">
-        <span>猫王吟游乡村之旅</span>
-      </el-form-item>
-      <el-form-item label="电台网址:">
-        <el-link :underline="false" href="">www.baidu.com</el-link>
-      </el-form-item>
-      <el-form-item label="当前状态:">
-        <span>下线</span>
-      </el-form-item>
-      <el-form-item label="故障次数:">
-        <span>3</span>
-      </el-form-item>
-      <el-form-item label="最新故障时间:">
-        <span>2022-05-10 18:00:00</span>
-      </el-form-item>
-      <el-form-item label="监控:">
-        <el-select placeholder="是否开启监控">
-          <el-option />
-        </el-select>
-      </el-form-item>
-      <el-form-item label="故障日志:">
-        <el-input type="textarea" rows="10" readonly />
-      </el-form-item>
-      <el-form-item>
-        <el-button @click="cancel">取消</el-button>
-        <el-button type="primary">确定</el-button>
-      </el-form-item>
-    </el-form>
-  </div>
-</template>
-
-<script>
-export default {
-  data() {
-    return {
-
-    }
-  },
-  methods:{
-    // 取消
-    cancel(){
-      this.$tab.closeOpenPage("/content/autoFM");
-    }
-  }
-}
-</script>
-
-<style lang="scss" scoped>
-.el-form{
-  width: 500px;
-}
-</style>

+ 0 - 61
src/views/content/autoFM/index.vue

@@ -1,61 +0,0 @@
-<template>
-  <div class="app-container">
-    <!-- 搜索 -->
-    <el-form inline label-width="100px" size="mini">
-      <el-form-item label="当前状态:">
-        <el-select placeholder="请选择当前状态">
-          <el-option />
-        </el-select>
-      </el-form-item>
-      <el-form-item label="电台名称:">
-        <el-input 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">
-      <el-table-column label="海外电台ID" align="center" />
-      <el-table-column label="电台名称" align="center" />
-      <el-table-column label="当前状态" align="center" />
-      <el-table-column label="监控" align="center" />
-      <el-table-column label="故障次数" align="center" />
-      <el-table-column label="最新故障时间" align="center" />
-      <el-table-column label="操作" align="center">
-        <el-button type="text" @click="getEdit">编辑</el-button>
-      </el-table-column>
-    </el-table>
-  </div>
-</template>
-
-<script>
-export default {
-  data() {
-    return {
-      tableData:[{
-        id: 1
-      }]
-    }
-  },
-  methods:{
-    // 搜索
-    getSearch(){
-
-    },
-    // 重置
-    getRefresh(){
-
-    },
-    getEdit(){
-      this.$router.push({
-        path: `/content/autoFM/detail`
-      })
-    }
-  }
-}
-</script>
-
-<style lang="scss" scoped>
-</style>

+ 0 - 150
src/views/content/banner/detail.vue

@@ -1,150 +0,0 @@
-<template>
-  <div class="app-container">
-    <el-form :model="form" label-width="110px">
-      <el-form-item label="Banner位置:">
-        <el-select v-model="form.type" placeholder="请选择Banner位置">
-          <el-option v-for="item in locationOptions" :key="item.value" :label="item.label"
-            :value="Number(item.value)" />
-        </el-select>
-      </el-form-item>
-      <el-form-item label="Banner名称:">
-        <el-input v-model="form.name" placeholder="请输入Banner名称" />
-      </el-form-item>
-      <el-form-item label="展示顺序:">
-        <el-input-number v-model="form.sort" :min="1" />
-      </el-form-item>
-      <el-form-item label="跳转地址:">
-        <el-radio-group v-model="form.forwardType">
-          <el-radio :label="0">内部</el-radio>
-          <el-radio :label="1">外部</el-radio>
-        </el-radio-group>
-        <el-select v-model="form.forwardLocation" v-if="form.forwardType === 0" placeholder="请选择跳转位置"
-          style="margin: 15px 0 20px 0">
-          <el-option v-for="item in addressOptions" :key="item.value" :label="item.label"
-            :value="Number(item.value)" />
-        </el-select>
-        <el-input v-model="form.forwardUrl" placeholder="请输入跳转链接地址"></el-input>
-      </el-form-item>
-      <el-form-item label="时间:">
-        <el-date-picker v-model="date" type="datetimerange" start-placeholder="开始时间" end-placeholder="结束时间"
-          value-format="yyyy-MM-dd HH:mm:ss" />
-      </el-form-item>
-      <el-form-item label="图片上传:">
-        <Upload listType="picture-card" :url="form.pic" @upload="getUpload" />
-      </el-form-item>
-    </el-form>
-    <div class="form-btn">
-      <el-button @click="cancel">取消</el-button>
-      <el-button type="primary" @click="getSubmit">提交</el-button>
-    </div>
-  </div>
-</template>
-
-<script>
-import { submit, detail, edit } from '@/api/content/banner'
-export default {
-  data() {
-    return {
-      date: '',
-      form: {
-        sort: 1,
-        forwardType: 0
-      },
-      // 展示位置
-      locationOptions: [{
-        value: 1,
-        label: '首页-推荐'
-      }, {
-        value: 2,
-        label: '电台-首页'
-      }, {
-        value: 3,
-        label: '音乐-首页'
-      }, {
-        value: 5,
-        label: '喵舍-推荐'
-      }, {
-        value: 4,
-        label: '服务中心-音乐'
-      }, {
-        value: 6,
-        label: '服务中心-流量'
-      }, {
-        value: 7,
-        label: '服务中心-底部热门专辑'
-      }],
-      // 跳转地址
-      addressOptions:[{
-        value: 1,
-        label: '服务中心'
-      }, {
-        value: 2,
-        label: '喵舍'
-      }, {
-        value: 3,
-        label: '签到'
-      }]
-    }
-  },
-  watch: {
-    date(val) {
-      this.form.startTime = val[0]
-      this.form.endTime = val[1]
-    }
-  },
-  mounted() {
-    if (this.$route.query.id) {
-      this.getList()
-    }
-  },
-  methods: {
-    // 详情
-    getList() {
-      detail({
-        id: this.$route.query.id
-      }).then(res => {
-        if (res.code === 0) {
-          this.form = res.data
-          this.date = [res.data.startTime, res.data.endTime]
-        }
-      })
-    },
-    // 上传
-    getUpload(e) {
-      this.form.pic = e.file
-    },
-    // 取消
-    cancel() {
-      this.$tab.closeOpenPage("/content/banner");
-    },
-    // 提交
-    getSubmit() {
-      if (this.$route.query.id) {
-        edit(this.form).then(res => {
-          if (res.code === 0) {
-            this.$message.success('修改成功!')
-            this.cancel()
-          }
-        })
-      } else {
-        submit(this.form).then(res => {
-          if (res.code === 0) {
-            this.$message.success('新增成功!')
-            this.cancel()
-          }
-        })
-      }
-    }
-  }
-}
-</script>
-
-<style lang="scss" scoped>
-.el-form {
-  width: 500px;
-}
-
-.form-btn {
-  margin-left: 110px;
-}
-</style>

+ 0 - 198
src/views/content/banner/index.vue

@@ -1,198 +0,0 @@
-<template>
-  <div class="app-container">
-    <!-- 搜索 -->
-    <el-form inline label-width="110px" size="mini">
-      <el-form-item label="Banner名称:">
-        <el-input v-model="form.name" placeholder="请输入名称" />
-      </el-form-item>
-      <el-form-item label="展示位置:">
-        <el-select v-model="form.type" placeholder="请选择展示位置">
-          <el-option v-for="item in locationOptions" :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="请选择当前状态">
-          <el-option v-for="item in currentOptions" :key="item.value" :label="item.label" :value="item.value" />
-        </el-select>
-      </el-form-item>
-      <el-form-item label="上/下架:">
-        <el-select v-model="form.shelfStatus" placeholder="请选择上/下架状态">
-          <el-option v-for="item in disabledOptions" :key="item.value" :label="item.label" :value="item.value" />
-        </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"
-          v-hasPermi="['content:banner:add']">新增</el-button>
-      </el-form-item>
-    </el-form>
-    <!-- 列表 -->
-    <el-table :data="tableData" v-loading="loading">
-      <el-table-column label="Banner名称" prop="name" align="center" />
-      <el-table-column label="Banner位置" prop="type" align="center" :formatter="typeFormatter" />
-      <el-table-column label="轮播顺序" prop="sort" align="center" />
-      <el-table-column label="图片" align="center" width="100px">
-        <template slot-scope="scope">
-          <el-image :src="scope.row.pic" />
-        </template>
-      </el-table-column>
-      <el-table-column label="当前状态" prop="currentStatus" align="center" :formatter="currentFormatter" />
-      <el-table-column label="上/下架" prop="status" align="center" :formatter="statusFormatter" />
-      <el-table-column label="开始时间" prop="startTime" align="center" />
-      <el-table-column label="结束时间" prop="endTime" align="center" />
-      <el-table-column label="操作" align="center">
-        <template slot-scope="scope">
-          <el-button v-if="scope.row.status === 1" type="text" @click="getChange(scope.row, 0)"
-            v-hasPermi="['content:banner:down']">下架</el-button>
-          <div v-else>
-            <el-button type="text" @click="getDetail(scope.row)" v-hasPermi="['content:banner:edit']">
-              编辑
-            </el-button>
-            <el-button type="text" @click="getChange(scope.row, 1)" v-hasPermi="['content:banner:up']">
-              上架
-            </el-button>
-            <el-button v-if="scope.row.status === 0" type="delete" @click="getDelete(scope.row)"
-              v-hasPermi="['content:banner:delete']">
-              删除
-            </el-button>
-          </div>
-        </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 { page, changeStatus, remove } from '@/api/content/banner'
-import { disabledMixin, currentMixin } from '@/mixin/index'
-export default {
-  mixins: [disabledMixin, currentMixin],
-  data() {
-    return {
-      // 遮罩层
-      loading: false,
-      // 表单
-      form: {
-        pageNum: 1,
-        pageSize: 10
-      },
-      total: 0,
-      // 列表
-      tableData: [],
-      // 展示位置
-      locationOptions: [{
-        value: 1,
-        label: '首页-推荐'
-      }, {
-        value: 2,
-        label: '电台-首页'
-      }, {
-        value: 3,
-        label: '音乐-首页'
-      }, {
-        value: 5,
-        label: '喵舍-推荐'
-      }, {
-        value: 4,
-        label: '服务中心-音乐'
-      }, {
-        value: 6,
-        label: '服务中心-流量'
-      }, {
-        value: 7,
-        label: '服务中心-底部热门专辑'
-      }]
-    }
-  },
-  mounted() {
-    this.getList()
-  },
-  methods: {
-    // 搜索
-    getSearch() {
-      this.form.pageNum = 1
-      this.form.pageSize = 10
-      this.getList()
-    },
-
-    // 重置
-    getRefresh() {
-      this.form = {
-        pageNum: 1,
-        pageSize: 10
-      }
-      this.getList()
-    },
-
-    // 分页
-    getList() {
-      this.loading = true
-      page(this.form).then(res => {
-        if (res.code === 0) {
-          this.tableData = res.data.records
-          this.total = res.data.total
-          this.loading = false
-        }
-      })
-    },
-
-    // 上下架
-    getChange(row, status) {
-      let tips = status === 0 ? '下架' : '上架'
-      changeStatus({
-        id: row.id,
-        status: status
-      }).then(res => {
-        if (res.code === 0) {
-          this.$message.success(`${tips}成功!`)
-          this.getList()
-        }
-      })
-    },
-
-    // 删除
-    getDelete(row) {
-      this.$confirm(`是否删除${row.name}`, '提示', {
-        confirmButtonText: '确认',
-        cancelButtonText: '取消',
-        type: 'warning'
-      }).then(() => {
-        remove({
-          id: row.id
-        }).then(res => {
-          if (res.code === 0) {
-            this.$message.success('删除成功!')
-            this.getList()
-          }
-        })
-      }).catch(() => {
-        this.$message.info('取消删除!')
-      })
-    },
-
-    // 新增 编辑
-    getDetail(row) {
-      this.$router.push({
-        path: '/content/banner/detail',
-        query: {
-          id: row.id
-        }
-      })
-    },
-
-    // 字典翻译
-    statusFormatter(row) {
-      return this.selectDictLabel(this.disabledOptions, row.status)
-    },
-    typeFormatter(row) {
-      return this.selectDictLabel(this.locationOptions, row.type)
-    },
-    currentFormatter(row) {
-      return this.selectDictLabel(this.currentOptions, row.currentStatus)
-    }
-  }
-}
-</script>

+ 4 - 1
src/views/device/list/detail.vue

@@ -50,7 +50,7 @@
       <div class="sub-form" v-for="(item, index) in form.typeList" :key="item.id">
         <el-form-item label="设备模式:" :prop="`typeList.${index}.type`"
           :rules="{ required: true, message: '请选择设备模式', trigger: 'change' }">
-          <el-select v-model="item.type" placeholder="请选择设备模式" @change="getTypeChange($event, index)">
+          <el-select v-model="item.type" placeholder="请选择设备模式" @change="getTypeChange">
             <el-option v-for="item in typeOptions" :key="item.value" :label="item.label" :value="Number(item.value)"
               :disabled="item.disabled" />
           </el-select>
@@ -234,6 +234,9 @@ export default {
         this.typeOptions[i].disabled = false
       }
       this.form.typeList.map(i => {
+        i.functionList = []
+        i.connectType = null
+        i.guidePageContent = ''
         if (i.type) {
           let index = this.typeOptions.findIndex(j => j.value == i.type)
           this.typeOptions[index].disabled = true

+ 13 - 11
src/views/music/album/index.vue

@@ -2,31 +2,33 @@
   <div class="app-container">
     <!-- 搜索 -->
     <el-form inline size="mini">
+      <el-form-item label="专辑Id:">
+        <el-input v-model="form.id" placeholder="请输入专辑Id" clearable />
+      </el-form-item>
       <el-form-item label="专辑名称:">
         <el-input v-model="form.name" placeholder="请输入专辑名称" clearable />
       </el-form-item>
+      <el-form-item label="歌手名称:">
+        <el-input v-model="form.singerName" placeholder="请输入歌手名称" clearable />
+      </el-form-item>
       <el-form-item label="资源平台:">
         <el-select v-model="form.platformId" placeholder="请选择资源平台" clearable>
-          <el-option v-for="item in platformOptions" :key="item.value" :value="item.value"
-            :label="item.label" />
+          <el-option v-for="item in platformOptions" :key="item.value" :value="item.value" :label="item.label" />
         </el-select>
       </el-form-item>
       <el-form-item label="专辑类型:">
         <el-select v-model="form.albumType" placeholder="请选择专辑类型" clearable>
-          <el-option v-for="item in albumTypeOptions" :key="item.value" :value="item.value"
-            :label="item.label" />
+          <el-option v-for="item in albumTypeOptions" :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="请选择付费类型" clearable>
-          <el-option v-for="item in payTypeOptions" :key="item.value" :value="item.value"
-            :label="item.label" />
+          <el-option v-for="item in payTypeOptions" :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="请选择当前状态" clearable>
-          <el-option v-for="item in onOrOffOptions" :key="item.value" :value="item.value"
-            :label="item.label" />
+          <el-option v-for="item in onOrOffOptions" :key="item.value" :value="item.value" :label="item.label" />
         </el-select>
       </el-form-item>
       <el-form-item>
@@ -50,8 +52,8 @@
           <el-image v-if="scope.row.coverUrl" :src="scope.row.coverUrl" />
         </template>
       </el-table-column>
-      <el-table-column label="专辑类型" prop="albumType" align="center" :formatter="typeFormatter"
-        show-overflow-tooltip />
+      <el-table-column label="专辑类型" prop="albumType" align="center" :formatter="typeFormatter" show-overflow-tooltip />
+      <el-table-column label="歌手名称" prop="singerName" align="center" show-overflow-tooltip />
       <el-table-column label="付费类型" prop="payType" align="center" :formatter="payTypeFormatter" />
       <el-table-column label="歌曲数量" prop="programCount" align="center" />
       <el-table-column label="资源平台" prop="platformId" align="center" :formatter="platformFormatter" />
@@ -79,7 +81,7 @@
         </template>
       </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" />
   </div>
 </template>

+ 6 - 0
src/views/music/monitor/index.vue

@@ -22,9 +22,15 @@
     </el-form>
     <!-- 列表 -->
     <el-table :data="tableData" v-loading="loading">
+      <el-table-column label="序号" type="index" align="center" />
       <el-table-column label="异常ID" prop="id" align="center" show-overflow-tooltip />
       <el-table-column label="音频ID" prop="audioId" align="center" show-overflow-tooltip />
       <el-table-column label="音频名称" prop="name" align="center" show-overflow-tooltip />
+      <el-table-column label="音频封面" align="center" width="100px">
+        <template slot-scope="scope">
+          <el-image v-if="scope.row.thumb" :src="scope.row.thumb" />
+        </template>
+      </el-table-column>
       <el-table-column label="音频类型" prop="audioType" align="center" :formatter="audioTypeFormatter" />
       <el-table-column label="资源平台" prop="platformId" align="center" :formatter="platformIdFormatter" />
       <el-table-column label="异常时间" align="center">

+ 7 - 2
src/views/operation/channel/detail.vue

@@ -10,7 +10,7 @@
           <el-form-item label="频道属性:">
             <el-select v-model="form.channelType" placeholder="请选择频道属性" :disabled="disabled" @change="handleChange">
               <el-option v-for="item in channelTypeOptions" :key="item.value" :value="Number(item.value)"
-                :label="item.label" />
+                :label="item.label" :disabled="channelDisabled(item.value)" />
             </el-select>
           </el-form-item>
           <el-form-item label="频道封面:">
@@ -88,7 +88,7 @@ export default {
       // 表单
       form: {},
       // 频道1 频道2 的频道属性不可修改
-      disabled: this.$route.query.index == '0' || this.$route.query.index == '1' ? true : false,
+      disabled: this.$route.query.index == '1' ? true : false,
       channelTypeOptions: [
         { value: 2, label: '广播' },
         { value: 6, label: '节目' },
@@ -163,6 +163,11 @@ export default {
       this.$tab.closeOpenPage('/operation/channel')
     },
 
+    // 除了2频道都不可以选猫王精选电台
+    channelDisabled(e){
+      return this.$route.query.index !== '1' ? e == 17 ? true : false : false
+    },
+
     // 字典翻译
     platfromFormatter(row) {
       return this.selectDictLabel(this.platformTypeOptions, row.platformId)

+ 100 - 0
src/views/operation/feedbacklist/detail.vue

@@ -0,0 +1,100 @@
+<template>
+  <div class='app-container'>
+    <el-form :model="form" ref="form" :rules="rules" label-width="100px">
+      <el-form-item label="用户Id:">
+        <span>{{ form.uid }}</span>
+      </el-form-item>
+      <el-form-item label="手机号:">
+        <span>{{ form.phone }}</span>
+      </el-form-item>
+      <el-form-item label="图片:">
+        <el-image v-for="item in form.url" :key="item" :src="item" :preview-src-list="form.url">
+          <span slot="error" />
+        </el-image>
+      </el-form-item>
+      <el-form-item label="反馈类型:">
+        <span>{{ form.type }}</span>
+      </el-form-item>
+      <el-form-item label="反馈内容:">
+        <span>{{ form.content }}</span>
+      </el-form-item>
+      <el-form-item v-if="reply" label="回复:" prop="reply" style="width: 500px;">
+        <el-input v-model="form.reply" type="textarea" :readonly="disabled" :autosize="{ minRows: 5, maxRows: 20 }"
+          placeholder="请输入回复" />
+      </el-form-item>
+    </el-form>
+    <div class="form-btn">
+      <el-button @click="close">取消</el-button>
+      <el-button v-if="!disabled" type="primary" @click="getSubmit">确定</el-button>
+    </div>
+  </div>
+</template>
+
+<script>
+import { detail, submit } from '@/api/operation/feedbacklist'
+export default {
+  data() {
+    return {
+      // 表单
+      form: {
+        id: this.$route.query.id
+      },
+      // 校验
+      rules: {
+        reply: [{
+          required: true, message: '请输入回复', trigger: 'blur'
+        }]
+      },
+      // 只读
+      disabled: this.$route.query.boolean ? Boolean(this.$route.query.boolean) : false
+    }
+  },
+  computed: {
+    reply() {
+      return this.disabled ? this.form.reply ? true : false : true
+    }
+  },
+  mounted() {
+    this.getDetail()
+  },
+  methods: {
+    // 详情
+    getDetail() {
+      detail(this.form.id).then(res => {
+        if (res.code === 0) {
+          this.form = res.data
+          this.form.url = res.data.url.split(',')
+        }
+      })
+    },
+
+    // 取消
+    close() {
+      this.$tab.closeOpenPage("/operation/feedback/feedbacklist");
+    },
+
+    // 提交
+    getSubmit() {
+      this.$refs.form.validate((valid) => {
+        if (valid) {
+          submit(this.form).then(res => {
+            if (res.code === 0) {
+              this.$message.success('提交成功!')
+              this.close()
+            }
+          })
+        } else {
+          return false
+        }
+      })
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.el-image {
+  width: 200px;
+  margin-right: 10px;
+}
+</style>

+ 139 - 0
src/views/operation/feedbacklist/index.vue

@@ -0,0 +1,139 @@
+<template>
+  <div class='app-container'>
+    <!-- 搜索 -->
+    <el-form inline size="mini">
+      <el-form-item label="用户Id:">
+        <el-input v-model="form.uid" placeholder="请输入用户Id" 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.type" placeholder="请选择反馈类型" clearable>
+          <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="反馈时间:">
+        <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="getDownload"
+          v-hasPermi="['operation:feedbacklist:download']">导出</el-button>
+      </el-form-item>
+    </el-form>
+    <!-- 列表 -->
+    <el-table :data="tableData" v-loading="loading">
+      <el-table-column label="序号" type="index" align="center" />
+      <el-table-column label="用户Id" prop="uid" align="center" show-overflow-tooltip />
+      <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.url.split(',')[0]">
+            <span slot="error">-</span>
+          </el-image>
+        </template>
+      </el-table-column>
+      <el-table-column label="反馈类型" prop="type" align="center" />
+      <el-table-column label="反馈内容" prop="content" align="center" show-overflow-tooltip />
+      <el-table-column label="回复" prop="reply" align="center" show-overflow-tooltip />
+      <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)"
+            v-hasPermi="['operation:feedbacklist:reply']">回复</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, typeList } from '@/api/operation/feedbacklist'
+export default {
+  data() {
+    return {
+      // 遮罩层
+      loading: false,
+      // 表单
+      form: {
+        pageNum: 1,
+        pageSize: 10
+      },
+      // 总数据
+      total: 0,
+      // 列表
+      tableData: [],
+      // 反馈类型
+      typeOptions: []
+    }
+  },
+  mounted() {
+    this.getList()
+    this.getTypeList()
+  },
+  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
+        }
+      })
+    },
+
+    // 反馈类型
+    getTypeList() {
+      typeList().then(res => {
+        if (res.code === 0) {
+          res.data.map(i => {
+            this.typeOptions.push({
+              value: i.id,
+              label: i.name
+            })
+          })
+        }
+      })
+    },
+
+    // 搜索
+    getSearch() {
+      this.form.pageNum = 1
+      this.getList()
+    },
+
+    // 重置
+    getRefresh() {
+      this.form = {
+        pageNum: 1,
+        pageSize: 10
+      }
+      this.getList()
+    },
+
+    // 导出
+    getDownload() {
+      this.download('/admin/opinions/excelDownload', this.form, '反馈列表.xlsx')
+    },
+
+    // 查看 回复
+    getDetail(id, boolean) {
+      this.$router.push({
+        path: `/operation/feedback/feedbacklist/detail`,
+        query: {
+          id: id,
+          boolean: boolean
+        }
+      })
+    }
+  }
+}
+</script>

+ 138 - 0
src/views/operation/feedbacktype/index.vue

@@ -0,0 +1,138 @@
+<template>
+  <div class='app-container'>
+    <el-button type="primary" icon="el-icon-plus" size="mini" @click="getDialog('新增')"
+      v-hasPermi="['operation:feedbacktype:add']">新增</el-button>
+    <!-- 列表 -->
+    <el-table :data="tableData" v-loading="loading">
+      <el-table-column label="序号" type="index" align="center"></el-table-column>
+      <el-table-column label="排序" prop="sort" align="center"></el-table-column>
+      <el-table-column label="类型名称" prop="name" align="center"></el-table-column>
+      <el-table-column label="创建时间" prop="createTime" align="center"></el-table-column>
+      <el-table-column label="操作" align="center">
+        <template slot-scope="scope">
+          <el-button type="text" @click="getDialog('编辑', scope.row.id)"
+            v-hasPermi="['operation:feedbacktype:edit']">编辑</el-button>
+          <el-button type="delete" @click="getDelete(scope.row)"
+            v-hasPermi="['operation:feedbacktype:delete']">删除</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" />
+    <!-- 弹窗 -->
+    <el-dialog :visible.sync="dialogVisible" :title="title" width="500px" :before-close="close">
+      <el-form :model="dialogForm" ref="dialogForm" :rules="rules" label-width="100px">
+        <el-form-item label="类型名称:" prop="name">
+          <el-input v-model="dialogForm.name" placeholder="请输入类型名称" />
+        </el-form-item>
+        <el-form-item label="排序:" prop="sort">
+          <el-input-number v-model="dialogForm.sort" :min="1" />
+        </el-form-item>
+      </el-form>
+      <div slot="footer">
+        <el-button @click="close">取消</el-button>
+        <el-button type="primary" @click="getSubmit">确定</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { list, detail, remove, submit } from '@/api/operation/feedbacktype'
+export default {
+  data() {
+    return {
+      // 遮罩层
+      loading: false,
+      // 表单
+      form: {
+        pageNum: 1,
+        pageSize: 10
+      },
+      // 总数据
+      total: 0,
+      // 列表
+      tableData: [],
+      // 弹窗
+      dialogVisible: false,
+      // 弹窗标题
+      title: '新增',
+      // 弹窗表单
+      dialogForm: {},
+      // 校验
+      rules: {
+        name: [{
+          required: true, message: '请输入类型名称', trigger: 'blur'
+        }],
+        sort: [{
+          required: true, message: '请输入排序', trigger: 'blur'
+        }]
+      }
+    }
+  },
+  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
+        }
+      })
+    },
+
+    // 删除
+    getDelete(row) {
+      this.$confirm(`是否删除${row.name}?`, '提示', {
+        type: "warning"
+      }).then(() => {
+        remove(row.id).then(res => {
+          if (res.code === 0) {
+            this.$message.success('删除成功!')
+            this.getList()
+          }
+        })
+      }).catch(() => { })
+    },
+
+    // 弹窗
+    getDialog(title, id) {
+      this.dialogVisible = true
+      this.title = title
+      if (id) {
+        detail(id).then(res => {
+          this.dialogForm = res.data
+        })
+      }
+    },
+
+    // 关闭
+    close() {
+      this.dialogVisible = false
+      this.dialogForm = {}
+    },
+
+    // 确定
+    getSubmit() {
+      this.$refs.dialogForm.validate((valid) => {
+        if (valid) {
+          submit(this.dialogForm).then(res => {
+            if (res.code === 0) {
+              this.$message.success('提交成功!')
+              this.close()
+              this.getList()
+            }
+          })
+        } else {
+          return false
+        }
+      })
+    }
+  }
+}
+</script>

+ 25 - 22
src/views/operation/recommend/detail.vue

@@ -529,31 +529,34 @@ export default {
     // 提交
     getSubmit() {
       let isValid = true
-      
-      this.$refs.list.map(i => i.validate((valid) => {
-        if (!valid) {
-          isValid = false
-          return false
-        }
-      }))
+      if (this.$refs.list) {
+        this.$refs.list.map(i => i.validate((valid) => {
+          if (!valid) {
+            isValid = false
+            return false
+          }
+        }))
 
-      if (isValid) {
-        // 区分2级新增 还是 3级编辑
-        this.$route.query.secondId ? this.form.secondId = this.$route.query.secondId : this.form.threeId = this.$route.query.threeId
-        // 删除仅作展示的缓存数据
-        for (const index in this.form.list) {
-          delete this.form.list[index].contentId
-          if ('description' in this.form.list[index]) {
-            this.form.list[index].module.description = this.form.list[index].description
-            delete this.form.list[index].description
+        if (isValid) {
+          // 区分2级新增 还是 3级编辑
+          this.$route.query.secondId ? this.form.secondId = this.$route.query.secondId : this.form.threeId = this.$route.query.threeId
+          // 删除仅作展示的缓存数据
+          for (const index in this.form.list) {
+            delete this.form.list[index].contentId
+            if ('description' in this.form.list[index]) {
+              this.form.list[index].module.description = this.form.list[index].description
+              delete this.form.list[index].description
+            }
           }
+          submitThree(this.form).then(res => {
+            if (res.code === 0) {
+              this.$message.success('提交成功!')
+              this.cancel()
+            }
+          })
         }
-        submitThree(this.form).then(res => {
-          if (res.code === 0) {
-            this.$message.success('提交成功!')
-            this.cancel()
-          }
-        })
+      }else{
+        this.$message.error('请添加新增内容')
       }
     },
 

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

@@ -254,7 +254,7 @@ export default {
     // 详情页
     getDetail(row, boolean) {
       this.$router.push({
-        path: `/operation/recommend/detail`,
+        path: `/operation/homePage/recommend/detail`,
         query: row.lv === 2 ? {
           secondId: row.id,
           moduleTypeId: row.moduleTypeId

+ 8 - 7
src/views/operation/tag/index.vue

@@ -7,8 +7,7 @@
       </el-form-item>
       <el-form-item label="当前状态:">
         <el-select v-model="form.status" placeholder="请选择当前状态" clearable>
-          <el-option v-for="item in disabledOptions" :key="item.value" :value="item.value"
-            :label="item.label" />
+          <el-option v-for="item in disabledOptions" :key="item.value" :value="item.value" :label="item.label" />
         </el-select>
       </el-form-item>
       <el-form-item>
@@ -19,9 +18,14 @@
       </el-form-item>
     </el-form>
     <!-- 列表 -->
-    <el-table :data="tableData" row-key="id" :tree-props="{children: 'children', hasChildren: 'hasChildren'}"
+    <el-table :data="tableData" row-key="id" :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
       v-loading="loading">
       <el-table-column label="标签名称" prop="label" show-overflow-tooltip />
+      <el-table-column label="标签Id" prop="id" align="center" show-overflow-tooltip>
+        <template slot-scope="scope">
+          <span>{{ scope.row.level === 3 ? scope.row.id : '-' }}</span>
+        </template>
+      </el-table-column>
       <el-table-column label="标签排序" prop="sort" align="center" />
       <el-table-column label="当前状态" prop="status" align="center">
         <template slot-scope="scope">
@@ -283,7 +287,4 @@ export default {
     }
   }
 }
-</script>
-
-<style lang="scss" scoped>
-</style>
+</script>

+ 13 - 8
src/views/project/list/detail.vue

@@ -10,7 +10,8 @@
       </el-form-item>
       <el-form-item v-if="projectForm.id" label="版本管理:" style="width: 100%;">
         <!-- app列表 -->
-        <el-button type="primary" icon="el-icon-plus" @click="getDialog()">新增</el-button>
+        <el-button type="primary" icon="el-icon-plus" @click="getDialog()"
+          v-hasPermi="['project:list:add']">新增</el-button>
         <el-table :data="versionData" v-loading="loading">
           <el-table-column type="index" label="序号" align="center" />
           <el-table-column prop="name" label="应用名称" align="center" show-overflow-tooltip />
@@ -25,11 +26,13 @@
           <el-table-column prop="status" label="当前状态" align="center" :formatter="statusFormatter" width="100px" />
           <el-table-column label="操作" align="center">
             <template slot-scope="scope">
-              <el-button v-if="scope.row.status === 0" type="text" @click="getShelves(scope.row, 1)">上架
+              <el-button v-if="scope.row.status === 0" type="text" @click="getShelves(scope.row, 1)"
+                v-hasPermi="['project:list:up']">上架
               </el-button>
-              <el-button v-else type="text" @click="getShelves(scope.row, 0)">下架</el-button>
+              <el-button v-else type="text" @click="getShelves(scope.row, 0)"
+                v-hasPermi="['project:list:down']">下架</el-button>
               <el-button type="text" @click="getDialog(scope.row, '更新')">更新</el-button>
-              <el-button type="text" @click="getDialog(scope.row, '编辑')">编辑</el-button>
+              <el-button type="text" @click="getDialog(scope.row, '编辑')" v-hasPermi="['project:list:edit']">编辑</el-button>
               <el-dropdown @command="getCommand($event, scope.row)" style="margin-left: 10px">
                 <el-button type="text">更多</el-button>
                 <el-dropdown-menu slot="dropdown">
@@ -47,7 +50,7 @@
     </el-form>
     <div class="form-btn">
       <el-button @click="cancel">取消</el-button>
-      <el-button type="primary" @click="getSubmit">确定</el-button>
+      <el-button type="primary" @click="getSubmit" v-hasPermi="['project:list:edit']">确定</el-button>
     </div>
 
     <!-- 新增弹窗 -->
@@ -93,11 +96,13 @@
         <el-table-column label="系统类型" prop="os" align="center" />
         <el-table-column label="更新时间" prop="updateTimeText" align="center" />
         <el-table-column label="当前状态" prop="status" align="center" :formatter="statusFormatter" />
-        <el-table-column lang="操作" align="center">
+        <el-table-column label="操作" align="center">
           <template slot-scope="scope">
-            <el-button v-if="scope.row.status === 0" type="text" @click="getShelves(scope.row, 1)">上架
+            <el-button v-if="scope.row.status === 0" type="text" @click="getShelves(scope.row, 1)"
+              v-hasPermi="['project:list:up']">上架
             </el-button>
-            <el-button v-else type="text" @click="getShelves(scope.row, 0)">下架</el-button>
+            <el-button v-else type="text" @click="getShelves(scope.row, 0)"
+              v-hasPermi="['project:list:down']">下架</el-button>
           </template>
         </el-table-column>
       </el-table>

+ 8 - 10
src/views/project/list/index.vue

@@ -13,7 +13,8 @@
       <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-button type="primary" icon="el-icon-plus" plain @click="getDetail()"
+          v-hasPermi="['project:list:add']">新增</el-button>
       </el-form-item>
     </el-form>
     <!-- 列表 -->
@@ -28,19 +29,16 @@
       <el-table-column label="操作" align="center">
         <template slot-scope="scope">
           <el-button type="text" @click="getDetail(scope.row, 'edit')">管理</el-button>
-          <el-button v-if="scope.row.status === 1" type="text" @click="getChange(scope.row, '上架')">上架</el-button>
-          <el-button v-else type="text" @click="getChange(scope.row, '下架')">下架</el-button>
+          <el-button v-if="scope.row.status === 1" type="text" @click="getChange(scope.row, '上架')"
+            v-hasPermi="['project:list:up']">上架</el-button>
+          <el-button v-else type="text" @click="getChange(scope.row, '下架')"
+            v-hasPermi="['project:list:down']">下架</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"
-    />
+    <pagination v-show="total > 0" :total="total" :page.sync="form.pageNum" :limit.sync="form.pageSize"
+      @pagination="getList" />
   </div>
 </template>
 

+ 9 - 12
src/views/service/qqmusic/index.vue

@@ -30,23 +30,20 @@
         <el-button type="primary" icon="el-icon-search" @click="getSearch">搜索</el-button>
         <el-button icon="el-icon-refresh" @click="getRefresh">重置</el-button>
         <Upload action="/qqService/importData" @upload="getUpload" style="margin: 0 10px"
-          v-hasPermi="['service:qqmusic:push']">批量推送短信</Upload>
-        <el-button type="danger" @click="getDialog()" v-hasPermi="['service:qqmusic:over']">批量过期</el-button>
+          v-hasPermi="['service:platform:push']">批量推送短信</Upload>
+        <el-button type="danger" @click="getDialog()" v-hasPermi="['service:platform:over']">批量过期</el-button>
         <el-button type="text" @click="getTemplate">模板下载</el-button>
       </el-form-item>
     </el-form>
     <!-- 列表 -->
     <el-table :data="tableData" v-loading="loading">
       <el-table-column label="批次" prop="no" align="center" show-overflow-tooltip />
-      <el-table-column label="购买套餐" prop="name" align="center" :formatter="nameFormatter" />
-      <el-table-column label="用户姓名" prop="userName" align="center" :formatter="userNameFormatter" />
-      <el-table-column label="用户手机号" prop="phone" align="center" :formatter="phoneFormatter" />
       <el-table-column label="服务时长" prop="serviceTime" align="center" :formatter="timeFormatter" />
       <el-table-column label="Key" prop="key" align="center" show-overflow-tooltip />
       <el-table-column label="发送时间" prop="sendTime" align="center" show-overflow-tooltip />
       <el-table-column label="当前状态" prop="codeStatus" align="center" :formatter="statusFormatter" />
       <el-table-column label="是否激活" prop="activeStatus" align="center" :formatter="activeStatusFormatter" />
-      <el-table-column label="操作">
+      <el-table-column label="操作" align="center">
         <template slot-scope="scope">
           <el-button type="text" @click="getDialog(scope.row)">查看</el-button>
           <el-button v-if="scope.row.codeStatus === 2" type="text">重新发送</el-button>
@@ -84,8 +81,8 @@
 
       <!-- 批量过期 -->
       <div v-else-if="title === '批量过期'">
-        <el-table :data="dialogData" height="429">
-          <el-table-column label="批次" prop="no" align="center" />
+        <el-table :data="dialogData">
+          <el-table-column label="批次" prop="no" align="center" show-overflow-tooltip />
           <el-table-column label="批次状态" prop="status" align="center" :formatter="batchFormatter" />
           <el-table-column label="批次人数" prop="num" align="center" />
           <el-table-column label="成功" prop="successNum" align="center" />
@@ -93,7 +90,7 @@
           <el-table-column label="添加日期" prop="createTime" align="center" show-overflow-tooltip />
           <el-table-column label="操作" align="center">
             <template slot-scope="scope">
-              <el-button type="delete" @click="getPast(scope.row)">强制过期</el-button>
+              <el-button type="delete" @click="getPast(scope.row)" :disabled="scope.row.status === 1">强制过期</el-button>
             </template>
           </el-table-column>
         </el-table>
@@ -116,7 +113,7 @@
           <el-descriptions-item label="发送时间">{{ dialogDetail.sendTime }}</el-descriptions-item>
           <el-descriptions-item label="激活账号">{{ dialogDetail.activeAccount }}</el-descriptions-item>
         </el-descriptions>
-        <el-button type="danger" @click="getPast(dialogDetail)" v-hasPermi="['service:qqmusic:over']">
+        <el-button type="danger" @click="getPast(dialogDetail)" v-hasPermi="['service:platform:over']">
           强制过期
         </el-button>
       </div>
@@ -125,7 +122,7 @@
 </template>
 
 <script>
-import { page, send, importData, detail, past, batchList, batchPage } from '@/api/service/qqmusic'
+import { page, send, importData, detail, past, batchList, batchPage } from '@/api/service/platform'
 import { serviceTimeMixin } from '@/mixin/index'
 export default {
   mixins: [serviceTimeMixin],
@@ -197,7 +194,7 @@ export default {
         }
       })
     },
-    
+
     // 搜索
     getSearch() {
       this.form.pageNum = 1

+ 128 - 0
src/views/service/record/index.vue

@@ -0,0 +1,128 @@
+<template>
+  <div class='app-container'>
+    <!-- 搜索 -->
+    <el-form inline size="mini">
+      <el-form-item label="批次号:">
+        <el-input v-model="form.no" placeholder="请输入批次号" clearable />
+      </el-form-item>
+      <el-form-item label="兑换码编码:">
+        <el-input v-model="form.code" placeholder="请输入兑换码编码" clearable />
+      </el-form-item>
+      <el-form-item label="设备标识:">
+        <el-input v-model="form.deviceMac" placeholder="请输入设备标识" clearable />
+      </el-form-item>
+      <el-form-item label="设备名称:">
+        <el-input v-model="form.deviceName" placeholder="请输入设备名称" clearable />
+      </el-form-item>
+      <el-form-item label="设备型号:">
+        <el-select v-model="form.clientType" filterable placeholder="请选择设备型号" clearable>
+          <el-option v-for="item in devOptions" :key="item.value" :value="item.value" :label="item.label" />
+        </el-select>
+      </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.serviceTime" placeholder="请选择服务时长" clearable>
+          <el-option v-for="item in serviceTimeOptions" :key="item.value" :value="item.value" :label="item.label" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="当前状态:">
+        <el-select v-model="form.activeStatus" placeholder="请选择当前状态" clearable>
+          <el-option v-for="item in statusOptions" :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-form-item>
+    </el-form>
+    <!-- 列表 -->
+    <el-table :data="tableData" v-loading="loading">
+      <el-table-column label="批次号" prop="no" align="center" show-overflow-tooltip />
+      <el-table-column label="兑换码编码" prop="code" align="center" show-overflow-tooltip />
+      <el-table-column label="设备标识" prop="deviceMac" align="center" show-overflow-tooltip />
+      <el-table-column label="设备型号" prop="clientType" align="center" show-overflow-tooltip />
+      <el-table-column label="设备名称" prop="deviceName" align="center" show-overflow-tooltip />
+      <el-table-column label="用户账号" prop="userName" align="center" />
+      <el-table-column label="用户手机号" prop="phone" align="center" />
+      <el-table-column label="服务时长" prop="serviceTime" align="center" :formatter="serviceFormatter" />
+      <el-table-column label="领取时间" prop="activeTime" align="center" />
+      <el-table-column label="创建时间" prop="createTime" align="center" />
+      <el-table-column label="当前状态" prop="activeStatus" align="center" :formatter="statusFormatter" />
+    </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/service/platform'
+import { serviceTimeMixin, devMixin } from '@/mixin/index'
+export default {
+  mixins: [serviceTimeMixin, devMixin],
+  data() {
+    return {
+      // 遮罩层
+      loading: false,
+      // 表单
+      form: {
+        pageNum: 1,
+        pageSize: 10
+      },
+      // 总数据
+      total: 0,
+      // 列表
+      tableData: [],
+      // 当前状态
+      statusOptions: [{
+        value: 0,
+        label: '未激活'
+      }, {
+        value: 1,
+        label: '已激活'
+      }]
+    }
+  },
+  mounted() {
+    this.getList()
+  },
+  methods: {
+    // 列表
+    getList() {
+      this.loading = true
+      list(this.form).then(res => {
+        console.log(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()
+    },
+
+    // 字典翻译
+    statusFormatter(row) {
+      return this.selectDictLabel(this.statusOptions, row.activeStatus)
+    },
+    serviceFormatter(row) {
+      return this.selectDictLabel(this.serviceTimeOptions, row.serviceTime)
+    }
+  }
+}
+</script>

+ 92 - 0
src/views/system/tts/index.vue

@@ -0,0 +1,92 @@
+<template>
+  <div class="app-container">
+    <el-row :gutter="20">
+      <el-col :span="20" :xs="24">
+        <el-row :gutter="10" class="mb8">
+          <el-col :span="1.5">
+            <el-button
+              type="primary"
+              plain
+              icon="el-icon-plus"
+              size="mini"
+              @click="handleAdd"
+              v-hasPermi="['system:tts:add']"
+            >新增
+            </el-button>
+          </el-col>
+        </el-row>
+      </el-col>
+    </el-row>
+
+    <!-- 对话框 -->
+    <el-dialog :title="title" :visible.sync="open" width="600px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="文本" prop="text">
+          <el-input v-model="form.text" placeholder="请输入语音文本" maxlength="200"/>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+
+export default {
+  data() {
+    return {
+      title: '转换语音',
+      // 遮罩层
+      loading: true,
+      // 是否显示弹出层
+      open: false,
+      // 表单参数
+      form: {
+        text: ''
+      },
+      // 表单校验
+      rules: {
+        text: [
+          { required: true, message: '语音文本不能为空', trigger: 'blur' },
+          { min: 1, max: 200, message: '语音文本长度必须介于 1 和 200 之间', trigger: 'blur' }
+        ]
+      }
+    }
+  },
+  created() {
+  },
+  methods: {
+    // 取消按钮
+    cancel() {
+      this.open = false
+      this.reset()
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        text: ''
+      }
+      this.resetForm('form')
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset()
+      this.open = true
+      this.title = '转换语音'
+    },
+    /** 提交按钮 */
+    submitForm: function() {
+      this.$refs['form'].validate(valid => {
+        if (valid) {
+          console.log(this.form)
+          this.open = false
+          this.$download.zip('/system/tts/getAudio?text=' + this.form.text, 'ruoyi')
+        }
+      })
+    }
+  }
+}
+</script>